Convert tabs to spaces
This commit is contained in:
parent
3acf60d6e9
commit
20c1ffd2fc
52
bin/pyircbot
52
bin/pyircbot
@ -7,29 +7,29 @@ from pyircbot import PyIRCBot
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
" logging level and facility "
|
||||
logging.basicConfig(level=logging.DEBUG, format="%(asctime)-15s %(levelname)-8s %(message)s")
|
||||
log = logging.getLogger('main')
|
||||
|
||||
" parse command line args "
|
||||
parser = OptionParser()
|
||||
parser.add_option("-c", "--config", action="store", type="string", dest="config", help="Path to config file")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
log.debug(options)
|
||||
|
||||
if not options.config:
|
||||
log.critical("No bot config file specified (-c). Exiting.")
|
||||
sys.exit(0)
|
||||
|
||||
botconfig = PyIRCBot.load(options.config)
|
||||
|
||||
log.debug(botconfig)
|
||||
|
||||
bot = PyIRCBot(botconfig)
|
||||
try:
|
||||
bot.loop()
|
||||
except KeyboardInterrupt:
|
||||
bot.kill()
|
||||
|
||||
" logging level and facility "
|
||||
logging.basicConfig(level=logging.DEBUG, format="%(asctime)-15s %(levelname)-8s %(message)s")
|
||||
log = logging.getLogger('main')
|
||||
|
||||
" parse command line args "
|
||||
parser = OptionParser()
|
||||
parser.add_option("-c", "--config", action="store", type="string", dest="config", help="Path to config file")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
log.debug(options)
|
||||
|
||||
if not options.config:
|
||||
log.critical("No bot config file specified (-c). Exiting.")
|
||||
sys.exit(0)
|
||||
|
||||
botconfig = PyIRCBot.load(options.config)
|
||||
|
||||
log.debug(botconfig)
|
||||
|
||||
bot = PyIRCBot(botconfig)
|
||||
try:
|
||||
bot.loop()
|
||||
except KeyboardInterrupt:
|
||||
bot.kill()
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""
|
||||
.. module:: Core
|
||||
:synopsis: Core module of the bot
|
||||
:synopsis: Core module of the bot
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""
|
||||
.. module:: ModuleBase
|
||||
:synopsis: Base class that modules will extend
|
||||
:synopsis: Base class that modules will extend
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -11,65 +11,65 @@ import os
|
||||
from .pyircbot import PyIRCBot
|
||||
|
||||
class ModuleBase:
|
||||
"""All modules will extend this class
|
||||
|
||||
:param bot: A reference to the main bot passed when this module is created
|
||||
:type bot: PyIRCBot
|
||||
:param moduleName: The name assigned to this module
|
||||
:type moduleName: str
|
||||
"""
|
||||
|
||||
def __init__(self, bot, moduleName):
|
||||
self.moduleName=moduleName
|
||||
"""Assigned name of this module"""
|
||||
|
||||
self.bot = bot
|
||||
"""Reference to the master PyIRCBot object"""
|
||||
|
||||
self.hooks=[]
|
||||
"""Hooks (aka listeners) this module has"""
|
||||
|
||||
self.services=[]
|
||||
"""If this module provides services usable by another module, they're listed
|
||||
here"""
|
||||
|
||||
self.config={}
|
||||
"""Configuration dictionary. Autoloaded from `%(datadir)s/%(modulename)s.json`"""
|
||||
|
||||
self.log = logging.getLogger("Module.%s" % self.moduleName)
|
||||
"""Logger object for this module"""
|
||||
|
||||
# Autoload config if available
|
||||
self.loadConfig()
|
||||
|
||||
self.log.info("Loaded module %s" % self.moduleName)
|
||||
|
||||
def loadConfig(self):
|
||||
"""Loads this module's config into self.config"""
|
||||
configPath = self.bot.getConfigPath(self.moduleName)
|
||||
if not configPath == None:
|
||||
self.config = PyIRCBot.load(configPath)
|
||||
|
||||
def ondisable(self):
|
||||
"""Called when the module should be disabled. Your module should do any sort
|
||||
of clean-up operations here like ending child threads or saving data files.
|
||||
"""
|
||||
pass
|
||||
|
||||
def getConfigPath(self):
|
||||
"""Returns the absolute path of this module's json config file"""
|
||||
return self.bot.getConfigPath(self.moduleName)
|
||||
|
||||
def getFilePath(self, f=None):
|
||||
"""Returns the absolute path to a file in this Module's data dir
|
||||
|
||||
:param f: The file name included in the path
|
||||
:type channel: str
|
||||
:Warning: .. Warning:: this does no error checking if the file exists or is\
|
||||
writable. The bot's data dir *should* always be writable"""
|
||||
return self.bot.getDataPath(self.moduleName) + (f if f else '')
|
||||
"""All modules will extend this class
|
||||
|
||||
:param bot: A reference to the main bot passed when this module is created
|
||||
:type bot: PyIRCBot
|
||||
:param moduleName: The name assigned to this module
|
||||
:type moduleName: str
|
||||
"""
|
||||
|
||||
def __init__(self, bot, moduleName):
|
||||
self.moduleName=moduleName
|
||||
"""Assigned name of this module"""
|
||||
|
||||
self.bot = bot
|
||||
"""Reference to the master PyIRCBot object"""
|
||||
|
||||
self.hooks=[]
|
||||
"""Hooks (aka listeners) this module has"""
|
||||
|
||||
self.services=[]
|
||||
"""If this module provides services usable by another module, they're listed
|
||||
here"""
|
||||
|
||||
self.config={}
|
||||
"""Configuration dictionary. Autoloaded from `%(datadir)s/%(modulename)s.json`"""
|
||||
|
||||
self.log = logging.getLogger("Module.%s" % self.moduleName)
|
||||
"""Logger object for this module"""
|
||||
|
||||
# Autoload config if available
|
||||
self.loadConfig()
|
||||
|
||||
self.log.info("Loaded module %s" % self.moduleName)
|
||||
|
||||
def loadConfig(self):
|
||||
"""Loads this module's config into self.config"""
|
||||
configPath = self.bot.getConfigPath(self.moduleName)
|
||||
if not configPath == None:
|
||||
self.config = PyIRCBot.load(configPath)
|
||||
|
||||
def ondisable(self):
|
||||
"""Called when the module should be disabled. Your module should do any sort
|
||||
of clean-up operations here like ending child threads or saving data files.
|
||||
"""
|
||||
pass
|
||||
|
||||
def getConfigPath(self):
|
||||
"""Returns the absolute path of this module's json config file"""
|
||||
return self.bot.getConfigPath(self.moduleName)
|
||||
|
||||
def getFilePath(self, f=None):
|
||||
"""Returns the absolute path to a file in this Module's data dir
|
||||
|
||||
:param f: The file name included in the path
|
||||
:type channel: str
|
||||
:Warning: .. Warning:: this does no error checking if the file exists or is\
|
||||
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
|
||||
def __init__(self, hook, method):
|
||||
self.hook=hook
|
||||
self.method=method
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: AttributeStorage
|
||||
:synopsis: An item key->value storage engine based on mysql
|
||||
:synopsis: An item key->value storage engine based on mysql
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -10,165 +10,165 @@
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
|
||||
class AttributeStorage(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.services=["attributes"]
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("mysql")
|
||||
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` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`attribute` varchar(128) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
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` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`item` varchar(512) CHARACTER SET utf8 NOT NULL,
|
||||
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` (
|
||||
`itemid` int(11) NOT NULL,
|
||||
`attributeid` int(11) NOT NULL,
|
||||
`value` varchar(512) CHARACTER SET utf8 NOT NULL,
|
||||
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
|
||||
`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`
|
||||
|
||||
WHERE
|
||||
`i`.`item`=%s;""",
|
||||
(name,)
|
||||
)
|
||||
item = {}
|
||||
while True:
|
||||
row = c.fetchone()
|
||||
if row == None:
|
||||
break
|
||||
item[row["attribute"]]=row["value"]
|
||||
c.close()
|
||||
|
||||
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
|
||||
: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
|
||||
`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`
|
||||
|
||||
WHERE
|
||||
`i`.`item`=%s
|
||||
AND
|
||||
`a`.`attribute`=%s;""",
|
||||
(item,key)
|
||||
)
|
||||
row = c.fetchone()
|
||||
c.close()
|
||||
if row == 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
|
||||
:type key: tuple
|
||||
:param value: the value to set
|
||||
: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:
|
||||
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:
|
||||
c = self.db.connection.query("INSERT INTO `items` (`item`) VALUES (%s);", (item))
|
||||
itemId = c.lastrowid
|
||||
else:
|
||||
itemId = row["id"]
|
||||
c.close()
|
||||
|
||||
if value == None:
|
||||
# delete it
|
||||
c = self.db.connection.query("DELETE FROM `values` WHERE `itemid`=%s AND `attributeid`=%s ;", (itemId, attributeId))
|
||||
self.log.debug("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))
|
||||
self.log.debug("AttributeStorage: Stored item %s attribute %s value: %s" % (itemId, attributeId, value))
|
||||
c.close()
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.services=["attributes"]
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("mysql")
|
||||
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` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`attribute` varchar(128) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
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` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`item` varchar(512) CHARACTER SET utf8 NOT NULL,
|
||||
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` (
|
||||
`itemid` int(11) NOT NULL,
|
||||
`attributeid` int(11) NOT NULL,
|
||||
`value` varchar(512) CHARACTER SET utf8 NOT NULL,
|
||||
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
|
||||
`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`
|
||||
|
||||
WHERE
|
||||
`i`.`item`=%s;""",
|
||||
(name,)
|
||||
)
|
||||
item = {}
|
||||
while True:
|
||||
row = c.fetchone()
|
||||
if row == None:
|
||||
break
|
||||
item[row["attribute"]]=row["value"]
|
||||
c.close()
|
||||
|
||||
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
|
||||
: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
|
||||
`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`
|
||||
|
||||
WHERE
|
||||
`i`.`item`=%s
|
||||
AND
|
||||
`a`.`attribute`=%s;""",
|
||||
(item,key)
|
||||
)
|
||||
row = c.fetchone()
|
||||
c.close()
|
||||
if row == 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
|
||||
:type key: tuple
|
||||
:param value: the value to set
|
||||
: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:
|
||||
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:
|
||||
c = self.db.connection.query("INSERT INTO `items` (`item`) VALUES (%s);", (item))
|
||||
itemId = c.lastrowid
|
||||
else:
|
||||
itemId = row["id"]
|
||||
c.close()
|
||||
|
||||
if value == None:
|
||||
# delete it
|
||||
c = self.db.connection.query("DELETE FROM `values` WHERE `itemid`=%s AND `attributeid`=%s ;", (itemId, attributeId))
|
||||
self.log.debug("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))
|
||||
self.log.debug("AttributeStorage: Stored item %s attribute %s value: %s" % (itemId, attributeId, value))
|
||||
c.close()
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: AttributeStorageLite
|
||||
:synopsis: An item key->value storage engine based on Sqlite
|
||||
:synopsis: An item key->value storage engine based on Sqlite
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -10,159 +10,159 @@
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
|
||||
class AttributeStorageLite(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.services=["attributes"]
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
if len(serviceProviders)==0:
|
||||
self.log.error("AttributeStorage: Could not find a valid sqlite service provider")
|
||||
else:
|
||||
self.log.info("AttributeStorage: Selecting sqlite service provider: %s" % serviceProviders[0])
|
||||
self.db = serviceProviders[0].opendb("attributes.db")
|
||||
|
||||
if not self.db.tableExists("attribute"):
|
||||
self.log.info("AttributeStorage: Creating table: attribute")
|
||||
c = self.db.query("""CREATE TABLE IF NOT EXISTS `attribute` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`attribute` varchar(128) UNIQUE
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
if not self.db.tableExists("items"):
|
||||
self.log.info("AttributeStorage: Creating table: items")
|
||||
c = self.db.query("""CREATE TABLE IF NOT EXISTS `items` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`item` varchar(512)
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
if not self.db.tableExists("values"):
|
||||
self.log.info("AttributeStorage: Creating table: values")
|
||||
c = self.db.query("""CREATE TABLE IF NOT EXISTS `values` (
|
||||
`itemid` INTEGER NOT NULL,
|
||||
`attributeid` INTEGER NOT NULL,
|
||||
`value` TEXT,
|
||||
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
|
||||
`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`
|
||||
|
||||
WHERE
|
||||
`i`.`item`=?;""",
|
||||
(name.lower(),)
|
||||
)
|
||||
item = {}
|
||||
while True:
|
||||
row = c.fetchone()
|
||||
if row == None:
|
||||
break
|
||||
item[row["attribute"]]=row["value"]
|
||||
c.close()
|
||||
|
||||
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
|
||||
: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
|
||||
`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`
|
||||
|
||||
WHERE
|
||||
`i`.`item`=?
|
||||
AND
|
||||
`a`.`attribute`=?;""",
|
||||
(item.lower(),key.lower())
|
||||
)
|
||||
row = c.fetchone()
|
||||
|
||||
c.close()
|
||||
if row == 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
|
||||
:type key: tuple
|
||||
:param value: the value to set
|
||||
: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:
|
||||
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:
|
||||
c = self.db.query("INSERT INTO `items` (`item`) VALUES (?);", (item,))
|
||||
itemId = c.lastrowid
|
||||
else:
|
||||
itemId = row["id"]
|
||||
c.close()
|
||||
|
||||
if value == None:
|
||||
# delete it
|
||||
c = self.db.query("DELETE FROM `values` WHERE `itemid`=? AND `attributeid`=? ;", (itemId, attributeId))
|
||||
self.log.debug("AttributeStorage: 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))
|
||||
self.log.debug("AttributeStorage: Stored item %s attribute %s value: %s" % (itemId, attributeId, value))
|
||||
c.close()
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.services=["attributes"]
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
if len(serviceProviders)==0:
|
||||
self.log.error("AttributeStorage: Could not find a valid sqlite service provider")
|
||||
else:
|
||||
self.log.info("AttributeStorage: Selecting sqlite service provider: %s" % serviceProviders[0])
|
||||
self.db = serviceProviders[0].opendb("attributes.db")
|
||||
|
||||
if not self.db.tableExists("attribute"):
|
||||
self.log.info("AttributeStorage: Creating table: attribute")
|
||||
c = self.db.query("""CREATE TABLE IF NOT EXISTS `attribute` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`attribute` varchar(128) UNIQUE
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
if not self.db.tableExists("items"):
|
||||
self.log.info("AttributeStorage: Creating table: items")
|
||||
c = self.db.query("""CREATE TABLE IF NOT EXISTS `items` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`item` varchar(512)
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
if not self.db.tableExists("values"):
|
||||
self.log.info("AttributeStorage: Creating table: values")
|
||||
c = self.db.query("""CREATE TABLE IF NOT EXISTS `values` (
|
||||
`itemid` INTEGER NOT NULL,
|
||||
`attributeid` INTEGER NOT NULL,
|
||||
`value` TEXT,
|
||||
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
|
||||
`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`
|
||||
|
||||
WHERE
|
||||
`i`.`item`=?;""",
|
||||
(name.lower(),)
|
||||
)
|
||||
item = {}
|
||||
while True:
|
||||
row = c.fetchone()
|
||||
if row == None:
|
||||
break
|
||||
item[row["attribute"]]=row["value"]
|
||||
c.close()
|
||||
|
||||
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
|
||||
: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
|
||||
`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`
|
||||
|
||||
WHERE
|
||||
`i`.`item`=?
|
||||
AND
|
||||
`a`.`attribute`=?;""",
|
||||
(item.lower(),key.lower())
|
||||
)
|
||||
row = c.fetchone()
|
||||
|
||||
c.close()
|
||||
if row == 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
|
||||
:type key: tuple
|
||||
:param value: the value to set
|
||||
: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:
|
||||
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:
|
||||
c = self.db.query("INSERT INTO `items` (`item`) VALUES (?);", (item,))
|
||||
itemId = c.lastrowid
|
||||
else:
|
||||
itemId = row["id"]
|
||||
c.close()
|
||||
|
||||
if value == None:
|
||||
# delete it
|
||||
c = self.db.query("DELETE FROM `values` WHERE `itemid`=? AND `attributeid`=? ;", (itemId, attributeId))
|
||||
self.log.debug("AttributeStorage: 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))
|
||||
self.log.debug("AttributeStorage: Stored item %s attribute %s value: %s" % (itemId, attributeId, value))
|
||||
c.close()
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""
|
||||
.. module:: BitcoinPrice
|
||||
:synopsis: Provides .bitcoin to show price indexes
|
||||
:synopsis: Provides .bitcoin to show price indexes
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -11,32 +11,32 @@ from requests import get
|
||||
from time import time
|
||||
|
||||
class BitcoinPrice(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
|
||||
self.cache = None
|
||||
self.cacheAge = 0
|
||||
|
||||
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]
|
||||
|
||||
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'])
|
||||
))
|
||||
|
||||
def getApi(self):
|
||||
if self.cache == 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
|
||||
|
||||
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
|
||||
self.cache = None
|
||||
self.cacheAge = 0
|
||||
|
||||
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]
|
||||
|
||||
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'])
|
||||
))
|
||||
|
||||
def getApi(self):
|
||||
if self.cache == 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
|
||||
|
||||
|
@ -4,258 +4,258 @@ 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={}
|
||||
|
||||
self.sqlite = self.bot.getBestModuleForService("sqlite")
|
||||
if self.sqlite==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("""
|
||||
CREATE TABLE `calc_addedby` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`username` varchar(32),
|
||||
`userhost` varchar(128)
|
||||
) ;
|
||||
""")
|
||||
c.close()
|
||||
if not self.sql.tableExists("calc_channels"):
|
||||
c = self.sql.getCursor()
|
||||
c.execute("""
|
||||
CREATE TABLE `calc_channels` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`channel` varchar(32)
|
||||
) ;
|
||||
""")
|
||||
if not self.sql.tableExists("calc_definitions"):
|
||||
c = self.sql.getCursor()
|
||||
c.execute("""
|
||||
CREATE TABLE `calc_definitions` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`word` INTEGET,
|
||||
`definition` varchar(512),
|
||||
`addedby` INTEGER,
|
||||
`date` timestamp,
|
||||
`status` varchar(16)
|
||||
) ;
|
||||
""")
|
||||
if not self.sql.tableExists("calc_words"):
|
||||
c = self.sql.getCursor()
|
||||
c.execute("""
|
||||
CREATE TABLE `calc_words` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`channel` INTEGER,
|
||||
`word` varchar(512),
|
||||
`status` varchar(32),
|
||||
unique(`channel`,`word`)
|
||||
);
|
||||
""")
|
||||
c.close()
|
||||
|
||||
def timeSince(self, channel, timetype):
|
||||
if not channel in self.timers:
|
||||
self.createDefaultTimers(channel)
|
||||
return time.time()-self.timers[channel][timetype]
|
||||
|
||||
def updateTimeSince(self, channel, timetype):
|
||||
if not channel 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}
|
||||
|
||||
def remainingToStr(self, total, elasped):
|
||||
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]=="#":
|
||||
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 foundCalc:
|
||||
calcCmd = trailing[len(cmd)-1:].strip()
|
||||
if "=" in calcCmd[1:]:
|
||||
" Add a new calc "
|
||||
calcWord, calcDefinition = calcCmd.split("=", 1)
|
||||
calcWord = calcWord.strip()
|
||||
calcDefinition = calcDefinition.strip()
|
||||
if self.config["allowDelete"] and calcDefinition == "":
|
||||
result = self.deleteCalc(args[0], calcWord)
|
||||
if result:
|
||||
self.bot.act_PRIVMSG(args[0], "Calc deleted, %s." % sender.nick)
|
||||
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")))
|
||||
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:
|
||||
" 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")))
|
||||
else:
|
||||
randCalc = self.getSpecificCalc(args[0], calcCmd)
|
||||
if randCalc==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.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")))
|
||||
else:
|
||||
randCalc = self.getRandomCalc(args[0])
|
||||
if randCalc == 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.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")))
|
||||
else:
|
||||
term = cmd.args_str
|
||||
if 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))
|
||||
rows = c.fetchall()
|
||||
if len(rows)==0:
|
||||
self.bot.act_PRIVMSG(args[0], "%s: Sorry, no matches" % sender.nick)
|
||||
else:
|
||||
matches = []
|
||||
for row in rows[0:10]:
|
||||
if row == None:
|
||||
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.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:
|
||||
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'))
|
||||
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.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()))
|
||||
word = c.fetchone()
|
||||
|
||||
if word == 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"], ))
|
||||
|
||||
who = c.fetchone()
|
||||
|
||||
if who == None:
|
||||
return None
|
||||
|
||||
c.close()
|
||||
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,))
|
||||
word = c.fetchone()
|
||||
if word == 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"], ))
|
||||
|
||||
who = c.fetchone()
|
||||
|
||||
if who == None:
|
||||
continue
|
||||
|
||||
c.close()
|
||||
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:
|
||||
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("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:
|
||||
c.execute("INSERT INTO `calc_channels` (`channel`) VALUES (?);", (channel,))
|
||||
c.execute("SELECT * FROM `calc_channels` WHERE `channel` = ?", (channel,))
|
||||
rows = c.fetchall()
|
||||
chId = rows[0]["id"]
|
||||
c.close()
|
||||
return chId
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.calc)]
|
||||
self.timers={}
|
||||
|
||||
self.sqlite = self.bot.getBestModuleForService("sqlite")
|
||||
if self.sqlite==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("""
|
||||
CREATE TABLE `calc_addedby` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`username` varchar(32),
|
||||
`userhost` varchar(128)
|
||||
) ;
|
||||
""")
|
||||
c.close()
|
||||
if not self.sql.tableExists("calc_channels"):
|
||||
c = self.sql.getCursor()
|
||||
c.execute("""
|
||||
CREATE TABLE `calc_channels` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`channel` varchar(32)
|
||||
) ;
|
||||
""")
|
||||
if not self.sql.tableExists("calc_definitions"):
|
||||
c = self.sql.getCursor()
|
||||
c.execute("""
|
||||
CREATE TABLE `calc_definitions` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`word` INTEGET,
|
||||
`definition` varchar(512),
|
||||
`addedby` INTEGER,
|
||||
`date` timestamp,
|
||||
`status` varchar(16)
|
||||
) ;
|
||||
""")
|
||||
if not self.sql.tableExists("calc_words"):
|
||||
c = self.sql.getCursor()
|
||||
c.execute("""
|
||||
CREATE TABLE `calc_words` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`channel` INTEGER,
|
||||
`word` varchar(512),
|
||||
`status` varchar(32),
|
||||
unique(`channel`,`word`)
|
||||
);
|
||||
""")
|
||||
c.close()
|
||||
|
||||
def timeSince(self, channel, timetype):
|
||||
if not channel in self.timers:
|
||||
self.createDefaultTimers(channel)
|
||||
return time.time()-self.timers[channel][timetype]
|
||||
|
||||
def updateTimeSince(self, channel, timetype):
|
||||
if not channel 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}
|
||||
|
||||
def remainingToStr(self, total, elasped):
|
||||
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]=="#":
|
||||
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 foundCalc:
|
||||
calcCmd = trailing[len(cmd)-1:].strip()
|
||||
if "=" in calcCmd[1:]:
|
||||
" Add a new calc "
|
||||
calcWord, calcDefinition = calcCmd.split("=", 1)
|
||||
calcWord = calcWord.strip()
|
||||
calcDefinition = calcDefinition.strip()
|
||||
if self.config["allowDelete"] and calcDefinition == "":
|
||||
result = self.deleteCalc(args[0], calcWord)
|
||||
if result:
|
||||
self.bot.act_PRIVMSG(args[0], "Calc deleted, %s." % sender.nick)
|
||||
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")))
|
||||
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:
|
||||
" 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")))
|
||||
else:
|
||||
randCalc = self.getSpecificCalc(args[0], calcCmd)
|
||||
if randCalc==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.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")))
|
||||
else:
|
||||
randCalc = self.getRandomCalc(args[0])
|
||||
if randCalc == 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.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")))
|
||||
else:
|
||||
term = cmd.args_str
|
||||
if 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))
|
||||
rows = c.fetchall()
|
||||
if len(rows)==0:
|
||||
self.bot.act_PRIVMSG(args[0], "%s: Sorry, no matches" % sender.nick)
|
||||
else:
|
||||
matches = []
|
||||
for row in rows[0:10]:
|
||||
if row == None:
|
||||
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.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:
|
||||
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'))
|
||||
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.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()))
|
||||
word = c.fetchone()
|
||||
|
||||
if word == 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"], ))
|
||||
|
||||
who = c.fetchone()
|
||||
|
||||
if who == None:
|
||||
return None
|
||||
|
||||
c.close()
|
||||
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,))
|
||||
word = c.fetchone()
|
||||
if word == 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"], ))
|
||||
|
||||
who = c.fetchone()
|
||||
|
||||
if who == None:
|
||||
continue
|
||||
|
||||
c.close()
|
||||
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:
|
||||
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("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:
|
||||
c.execute("INSERT INTO `calc_channels` (`channel`) VALUES (?);", (channel,))
|
||||
c.execute("SELECT * FROM `calc_channels` WHERE `channel` = ?", (channel,))
|
||||
rows = c.fetchall()
|
||||
chId = rows[0]["id"]
|
||||
c.close()
|
||||
return chId
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: Error
|
||||
:synopsis: Module to provide a multi-type cryptocurrency wallet
|
||||
:synopsis: Module to provide a multi-type cryptocurrency wallet
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -12,214 +12,214 @@ import time
|
||||
import hashlib
|
||||
|
||||
class CryptoWallet(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.gotmsg)]
|
||||
|
||||
def gotmsg(self, args, prefix, trailing):
|
||||
channel = args[0]
|
||||
if channel[0] == "#":
|
||||
# Ignore channel messages
|
||||
pass
|
||||
else:
|
||||
self.handlePm(args, prefix, trailing)
|
||||
|
||||
def getMods(self):
|
||||
return (self.bot.getBestModuleForService("attributes"), self.bot.getBestModuleForService("login"), self.bot.getBestModuleForService("bitcoinrpc"))
|
||||
|
||||
def handle_setaddr(self, args, prefix, trailing, cmd):
|
||||
usage = ".setaddr <currency> <address>"
|
||||
attr,login,rpc = self.getMods()
|
||||
# Check login
|
||||
if not login.check(prefix.nick, prefix.hostname):
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setaddr: Please .login to use this command.")
|
||||
return
|
||||
# Check for args
|
||||
if not len(cmd.args)==2:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setaddr: usage: %s" % usage)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".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(prefix.nick, ".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:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".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(prefix.nick, ".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,login,rpc = self.getMods()
|
||||
# Check login
|
||||
if not login.check(prefix.nick, prefix.hostname):
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getbal: Please .login to use this command.")
|
||||
return
|
||||
# Check for args
|
||||
if not len(cmd.args)==1:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getbal: usage: %s" % usage)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".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(prefix.nick, ".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())
|
||||
amount = 0.0
|
||||
if walletname:
|
||||
client = rpc.getRpc(cmd.args[0].lower())
|
||||
amount = client.getBal(walletname)
|
||||
self.bot.act_PRIVMSG(prefix.nick, "Your balance is: %s %s" % (amount, cmd.args[0].upper()))
|
||||
|
||||
def handle_withdraw(self, args, prefix, trailing, cmd):
|
||||
usage = ".withdraw <currency> <amount>"
|
||||
attr,login,rpc = self.getMods()
|
||||
# Check login
|
||||
if not login.check(prefix.nick, prefix.hostname):
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdraw: Please .login to use this command.")
|
||||
return
|
||||
# Check for args
|
||||
if not len(cmd.args)==2:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdraw: usage: %s" % usage)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".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(prefix.nick, ".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(prefix.nick, ".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())
|
||||
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(prefix.nick, ".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(prefix.nick, ".withdraw: Withdrawing that much would put you below the reserve (%s %s)." % (client.reserve, cmd.args[0].upper()))
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".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(prefix.nick, ".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(prefix.nick, ".withdraw: %s %s sent to %s. Transaction ID: %s"% (withdrawamount, client.name, withdrawaddr, txn))
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdraw: Transaction create failed. Maybe the transaction was too large for the network? Try a smaller increment.")
|
||||
|
||||
def handle_getaddr(self, args, prefix, trailing, cmd):
|
||||
attr,login,rpc = self.getMods()
|
||||
usage = ".getaddr <currency>"
|
||||
attr,login,rpc = self.getMods()
|
||||
# Check login
|
||||
if not login.check(prefix.nick, prefix.hostname):
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getaddr: Please .login to use this command.")
|
||||
return
|
||||
# Check for args
|
||||
if not len(cmd.args)==1:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getaddr: usage: %s" % usage)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".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(prefix.nick, ".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(prefix.nick, "Your %s deposit address is: %s" % (cmd.args[0].upper(), walletaddr))
|
||||
|
||||
def handle_curinfo(self, args, prefix, trailing, cmd):
|
||||
attr,login,rpc = self.getMods()
|
||||
usage = ".curinfo [<currency>]"
|
||||
attr,login,rpc = self.getMods()
|
||||
|
||||
# Check for args
|
||||
if len(cmd.args)==0:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".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(prefix.nick, ".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(prefix.nick, ".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,login,rpc = self.getMods()
|
||||
currency = currency.lower()
|
||||
if attr.getKey(username, "cryptowallet-account-%s"%currency)==None:
|
||||
randName = self.md5(str(time.time()))[0:16]
|
||||
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)
|
||||
wallet = rpc.getRpc(currency.lower())
|
||||
address = wallet.getAcctAddr(walletName)
|
||||
attr.setKey(username, "cryptowallet-depoaddr-%s"%currency, address)
|
||||
|
||||
|
||||
def handlePm(self, args, prefix, trailing):
|
||||
prefix = self.bot.decodePrefix(prefix)
|
||||
|
||||
cmd = self.bot.messageHasCommand(".setaddr", trailing)
|
||||
if cmd:
|
||||
self.handle_setaddr(args, prefix, trailing, cmd)
|
||||
cmd = self.bot.messageHasCommand(".getbal", trailing)
|
||||
if cmd:
|
||||
self.handle_getbal(args, prefix, trailing, cmd)
|
||||
cmd = self.bot.messageHasCommand(".withdraw", trailing)
|
||||
if cmd:
|
||||
self.handle_withdraw(args, prefix, trailing, cmd)
|
||||
cmd = self.bot.messageHasCommand(".getaddr", trailing)
|
||||
if cmd:
|
||||
self.handle_getaddr(args, prefix, trailing, cmd)
|
||||
cmd = self.bot.messageHasCommand(".curinfo", trailing)
|
||||
if cmd:
|
||||
self.handle_curinfo(args, prefix, trailing, cmd)
|
||||
|
||||
def md5(self, data):
|
||||
m = hashlib.md5()
|
||||
m.update(data.encode("ascii"))
|
||||
return m.hexdigest()
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.gotmsg)]
|
||||
|
||||
def gotmsg(self, args, prefix, trailing):
|
||||
channel = args[0]
|
||||
if channel[0] == "#":
|
||||
# Ignore channel messages
|
||||
pass
|
||||
else:
|
||||
self.handlePm(args, prefix, trailing)
|
||||
|
||||
def getMods(self):
|
||||
return (self.bot.getBestModuleForService("attributes"), self.bot.getBestModuleForService("login"), self.bot.getBestModuleForService("bitcoinrpc"))
|
||||
|
||||
def handle_setaddr(self, args, prefix, trailing, cmd):
|
||||
usage = ".setaddr <currency> <address>"
|
||||
attr,login,rpc = self.getMods()
|
||||
# Check login
|
||||
if not login.check(prefix.nick, prefix.hostname):
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setaddr: Please .login to use this command.")
|
||||
return
|
||||
# Check for args
|
||||
if not len(cmd.args)==2:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setaddr: usage: %s" % usage)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".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(prefix.nick, ".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:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".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(prefix.nick, ".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,login,rpc = self.getMods()
|
||||
# Check login
|
||||
if not login.check(prefix.nick, prefix.hostname):
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getbal: Please .login to use this command.")
|
||||
return
|
||||
# Check for args
|
||||
if not len(cmd.args)==1:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getbal: usage: %s" % usage)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".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(prefix.nick, ".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())
|
||||
amount = 0.0
|
||||
if walletname:
|
||||
client = rpc.getRpc(cmd.args[0].lower())
|
||||
amount = client.getBal(walletname)
|
||||
self.bot.act_PRIVMSG(prefix.nick, "Your balance is: %s %s" % (amount, cmd.args[0].upper()))
|
||||
|
||||
def handle_withdraw(self, args, prefix, trailing, cmd):
|
||||
usage = ".withdraw <currency> <amount>"
|
||||
attr,login,rpc = self.getMods()
|
||||
# Check login
|
||||
if not login.check(prefix.nick, prefix.hostname):
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdraw: Please .login to use this command.")
|
||||
return
|
||||
# Check for args
|
||||
if not len(cmd.args)==2:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdraw: usage: %s" % usage)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".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(prefix.nick, ".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(prefix.nick, ".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())
|
||||
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(prefix.nick, ".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(prefix.nick, ".withdraw: Withdrawing that much would put you below the reserve (%s %s)." % (client.reserve, cmd.args[0].upper()))
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".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(prefix.nick, ".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(prefix.nick, ".withdraw: %s %s sent to %s. Transaction ID: %s"% (withdrawamount, client.name, withdrawaddr, txn))
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdraw: Transaction create failed. Maybe the transaction was too large for the network? Try a smaller increment.")
|
||||
|
||||
def handle_getaddr(self, args, prefix, trailing, cmd):
|
||||
attr,login,rpc = self.getMods()
|
||||
usage = ".getaddr <currency>"
|
||||
attr,login,rpc = self.getMods()
|
||||
# Check login
|
||||
if not login.check(prefix.nick, prefix.hostname):
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getaddr: Please .login to use this command.")
|
||||
return
|
||||
# Check for args
|
||||
if not len(cmd.args)==1:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getaddr: usage: %s" % usage)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".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(prefix.nick, ".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(prefix.nick, "Your %s deposit address is: %s" % (cmd.args[0].upper(), walletaddr))
|
||||
|
||||
def handle_curinfo(self, args, prefix, trailing, cmd):
|
||||
attr,login,rpc = self.getMods()
|
||||
usage = ".curinfo [<currency>]"
|
||||
attr,login,rpc = self.getMods()
|
||||
|
||||
# Check for args
|
||||
if len(cmd.args)==0:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".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(prefix.nick, ".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(prefix.nick, ".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,login,rpc = self.getMods()
|
||||
currency = currency.lower()
|
||||
if attr.getKey(username, "cryptowallet-account-%s"%currency)==None:
|
||||
randName = self.md5(str(time.time()))[0:16]
|
||||
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)
|
||||
wallet = rpc.getRpc(currency.lower())
|
||||
address = wallet.getAcctAddr(walletName)
|
||||
attr.setKey(username, "cryptowallet-depoaddr-%s"%currency, address)
|
||||
|
||||
|
||||
def handlePm(self, args, prefix, trailing):
|
||||
prefix = self.bot.decodePrefix(prefix)
|
||||
|
||||
cmd = self.bot.messageHasCommand(".setaddr", trailing)
|
||||
if cmd:
|
||||
self.handle_setaddr(args, prefix, trailing, cmd)
|
||||
cmd = self.bot.messageHasCommand(".getbal", trailing)
|
||||
if cmd:
|
||||
self.handle_getbal(args, prefix, trailing, cmd)
|
||||
cmd = self.bot.messageHasCommand(".withdraw", trailing)
|
||||
if cmd:
|
||||
self.handle_withdraw(args, prefix, trailing, cmd)
|
||||
cmd = self.bot.messageHasCommand(".getaddr", trailing)
|
||||
if cmd:
|
||||
self.handle_getaddr(args, prefix, trailing, cmd)
|
||||
cmd = self.bot.messageHasCommand(".curinfo", trailing)
|
||||
if cmd:
|
||||
self.handle_curinfo(args, prefix, trailing, cmd)
|
||||
|
||||
def md5(self, data):
|
||||
m = hashlib.md5()
|
||||
m.update(data.encode("ascii"))
|
||||
return m.hexdigest()
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: CryptoWalletRPC
|
||||
:synopsis: Module capable of operating bitcoind-style RPC. Provided as a service.
|
||||
:synopsis: Module capable of operating bitcoind-style RPC. Provided as a service.
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -14,120 +14,120 @@ 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={}
|
||||
|
||||
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
|
||||
|
||||
def getRpc(self, currencyAbbr):
|
||||
# Return the rpc for the currency requested
|
||||
# self.getRpc("LTC") -> returns a litecoin rpc instance
|
||||
currencyAbbr = currencyAbbr.lower()
|
||||
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()]
|
||||
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.services=["bitcoinrpc"]
|
||||
self.loadConfig()
|
||||
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
|
||||
|
||||
def getRpc(self, currencyAbbr):
|
||||
# Return the rpc for the currency requested
|
||||
# self.getRpc("LTC") -> returns a litecoin rpc instance
|
||||
currencyAbbr = currencyAbbr.lower()
|
||||
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):
|
||||
# Store info and connect
|
||||
self.master = parent
|
||||
self.name = name
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.username = username
|
||||
self.password = password
|
||||
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
|
||||
return self.getAcctBal(acct)
|
||||
|
||||
def getAcctAddr(self, acct):
|
||||
# returns the address for an account. creates if necessary
|
||||
self.ping()
|
||||
addrs = self.con.getaddressesbyaccount(acct)
|
||||
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
|
||||
balfrom = self.getAcctBal(fromAcct)
|
||||
return balfrom >= amount
|
||||
|
||||
def move(self, fromAcct, toAcct, amount):
|
||||
# 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
|
||||
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.debug("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.debug("CryptoWalletRPC: %s: Could not connect to %s:%s: %s" % (self.name, self.host, self.port, str(e)))
|
||||
return
|
||||
|
||||
self.log.debug("CryptoWalletRPC: %s: Connected to %s:%s" % (self.name, self.host, self.port))
|
||||
|
||||
def __init__(self, parent, name, host, port, username, password, precision, reserve):
|
||||
# Store info and connect
|
||||
self.master = parent
|
||||
self.name = name
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.username = username
|
||||
self.password = password
|
||||
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
|
||||
return self.getAcctBal(acct)
|
||||
|
||||
def getAcctAddr(self, acct):
|
||||
# returns the address for an account. creates if necessary
|
||||
self.ping()
|
||||
addrs = self.con.getaddressesbyaccount(acct)
|
||||
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
|
||||
balfrom = self.getAcctBal(fromAcct)
|
||||
return balfrom >= amount
|
||||
|
||||
def move(self, fromAcct, toAcct, amount):
|
||||
# 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
|
||||
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.debug("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.debug("CryptoWalletRPC: %s: Could not connect to %s:%s: %s" % (self.name, self.host, self.port, str(e)))
|
||||
return
|
||||
|
||||
self.log.debug("CryptoWalletRPC: %s: Connected to %s:%s" % (self.name, self.host, self.port))
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: DogeDice
|
||||
:synopsis: Module to provide a game for gambling Dogecoin
|
||||
:synopsis: Module to provide a game for gambling Dogecoin
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -16,307 +16,307 @@ 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()
|
||||
# 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:
|
||||
# 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])
|
||||
# Channel message
|
||||
self.games[args[0]].gotMsg(args, prefix, trailing)
|
||||
else:
|
||||
# Private message
|
||||
#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:
|
||||
first = list(self.games.keys())[0]
|
||||
self.games[first].gameover()
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.gotMsg)]
|
||||
self.loadConfig()
|
||||
# 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:
|
||||
# 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])
|
||||
# Channel message
|
||||
self.games[args[0]].gotMsg(args, prefix, trailing)
|
||||
else:
|
||||
# Private message
|
||||
#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:
|
||||
first = list(self.games.keys())[0]
|
||||
self.games[first].gameover()
|
||||
|
||||
class gameObj:
|
||||
def __init__(self, master, channel):
|
||||
self.master = master
|
||||
self.channel = channel
|
||||
# Game state
|
||||
# 0 = waiting for players
|
||||
# - advertise self?
|
||||
# - players must be registered and have enough doge for current bet
|
||||
# 1 = enough players, countdown
|
||||
# - Last warning to pull out
|
||||
# 2 = locked in / game setup
|
||||
# - Move doge from player's wallets to table wallet. kick players if they can't afford
|
||||
# 3 = start of a round
|
||||
# - Each player's turn to roll
|
||||
# 4 = determine winner, move doge
|
||||
# - if > 10 doge, house fee?
|
||||
self.step = 0
|
||||
|
||||
# Bet amount
|
||||
self.bet = 0.0
|
||||
# players list
|
||||
self.players = []
|
||||
# min players
|
||||
self.minPlayers = 2
|
||||
# max players
|
||||
self.maxPlayers = 4
|
||||
# Lobby countdown timer
|
||||
self.startCountdownTimer = None
|
||||
# pre-result timer
|
||||
self.endgameResultTimer = None
|
||||
# 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:
|
||||
userWallet = self.master.attr.getKey(prefix.nick, "dogeaccountname")
|
||||
if userWallet == 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:
|
||||
# require an amount
|
||||
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"]))
|
||||
return
|
||||
|
||||
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))
|
||||
else:
|
||||
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:
|
||||
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:
|
||||
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))
|
||||
else:
|
||||
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))
|
||||
else:
|
||||
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:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: You're not in the game." % (prefix.nick))
|
||||
else:
|
||||
self.removePlayer(prefix.nick)
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: You have left the game!" % (prefix.nick))
|
||||
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.step = 0
|
||||
elif self.step == 2:
|
||||
pass
|
||||
elif self.step == 3:
|
||||
# Ignore cmds from people outside the game
|
||||
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)
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s rolls %s and %s!" % (prefix.nick, roll1, roll2))
|
||||
player.hasRolled = True
|
||||
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)):
|
||||
if self.players[i].nick == playerNick:
|
||||
pos = i
|
||||
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
|
||||
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
|
||||
# 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.")
|
||||
if self.step == 3:
|
||||
# In game step. Refund doges
|
||||
for player in self.players:
|
||||
self.master.doge.move(self.walletName, player.dogeWalletName, self.bet)
|
||||
self.resetGame()
|
||||
|
||||
def endgameResults(self):
|
||||
maxRollNames = []
|
||||
maxRollValue = 0
|
||||
for player in self.players:
|
||||
if player.rollValue > maxRollValue:
|
||||
maxRollNames = []
|
||||
maxRollNames.append(player.nick)
|
||||
maxRollValue = player.rollValue
|
||||
if player.rollValue == maxRollValue:
|
||||
if not player.nick 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))
|
||||
else:
|
||||
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
|
||||
self.clearTimer(self.endgameResultTimer)
|
||||
self.endgameResultTimer = None
|
||||
self.clearTimer(self.playTimeout)
|
||||
self.playTimeout = None
|
||||
self.master.removeGame(self.channel)
|
||||
|
||||
def gameover(self):
|
||||
self.gamePlayTimeoutExpired()
|
||||
|
||||
def __init__(self, master, channel):
|
||||
self.master = master
|
||||
self.channel = channel
|
||||
# Game state
|
||||
# 0 = waiting for players
|
||||
# - advertise self?
|
||||
# - players must be registered and have enough doge for current bet
|
||||
# 1 = enough players, countdown
|
||||
# - Last warning to pull out
|
||||
# 2 = locked in / game setup
|
||||
# - Move doge from player's wallets to table wallet. kick players if they can't afford
|
||||
# 3 = start of a round
|
||||
# - Each player's turn to roll
|
||||
# 4 = determine winner, move doge
|
||||
# - if > 10 doge, house fee?
|
||||
self.step = 0
|
||||
|
||||
# Bet amount
|
||||
self.bet = 0.0
|
||||
# players list
|
||||
self.players = []
|
||||
# min players
|
||||
self.minPlayers = 2
|
||||
# max players
|
||||
self.maxPlayers = 4
|
||||
# Lobby countdown timer
|
||||
self.startCountdownTimer = None
|
||||
# pre-result timer
|
||||
self.endgameResultTimer = None
|
||||
# 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:
|
||||
userWallet = self.master.attr.getKey(prefix.nick, "dogeaccountname")
|
||||
if userWallet == 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:
|
||||
# require an amount
|
||||
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"]))
|
||||
return
|
||||
|
||||
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))
|
||||
else:
|
||||
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:
|
||||
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:
|
||||
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))
|
||||
else:
|
||||
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))
|
||||
else:
|
||||
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:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: You're not in the game." % (prefix.nick))
|
||||
else:
|
||||
self.removePlayer(prefix.nick)
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: You have left the game!" % (prefix.nick))
|
||||
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.step = 0
|
||||
elif self.step == 2:
|
||||
pass
|
||||
elif self.step == 3:
|
||||
# Ignore cmds from people outside the game
|
||||
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)
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s rolls %s and %s!" % (prefix.nick, roll1, roll2))
|
||||
player.hasRolled = True
|
||||
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)):
|
||||
if self.players[i].nick == playerNick:
|
||||
pos = i
|
||||
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
|
||||
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
|
||||
# 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.")
|
||||
if self.step == 3:
|
||||
# In game step. Refund doges
|
||||
for player in self.players:
|
||||
self.master.doge.move(self.walletName, player.dogeWalletName, self.bet)
|
||||
self.resetGame()
|
||||
|
||||
def endgameResults(self):
|
||||
maxRollNames = []
|
||||
maxRollValue = 0
|
||||
for player in self.players:
|
||||
if player.rollValue > maxRollValue:
|
||||
maxRollNames = []
|
||||
maxRollNames.append(player.nick)
|
||||
maxRollValue = player.rollValue
|
||||
if player.rollValue == maxRollValue:
|
||||
if not player.nick 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))
|
||||
else:
|
||||
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
|
||||
self.clearTimer(self.endgameResultTimer)
|
||||
self.endgameResultTimer = None
|
||||
self.clearTimer(self.playTimeout)
|
||||
self.playTimeout = None
|
||||
self.master.removeGame(self.channel)
|
||||
|
||||
def gameover(self):
|
||||
self.gamePlayTimeoutExpired()
|
||||
|
||||
|
||||
class playerObj:
|
||||
def __init__(self, game, nick):
|
||||
self.game = game
|
||||
self.nick = nick
|
||||
# Save the player's wallet name
|
||||
self.dogeWalletName = None
|
||||
# Set to true after they roll
|
||||
self.hasRolled = False
|
||||
# Sum of their dice
|
||||
self.rollValue = None
|
||||
|
||||
def __init__(self, game, nick):
|
||||
self.game = game
|
||||
self.nick = nick
|
||||
# Save the player's wallet name
|
||||
self.dogeWalletName = None
|
||||
# Set to true after they roll
|
||||
self.hasRolled = False
|
||||
# Sum of their dice
|
||||
self.rollValue = None
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: DogeWallet
|
||||
:synopsis: Module to provide a Dogecoin wallet
|
||||
:synopsis: Module to provide a Dogecoin wallet
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -12,161 +12,161 @@ import time
|
||||
import hashlib
|
||||
|
||||
class DogeWallet(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
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] == "#":
|
||||
# Ignore channel messages
|
||||
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\"")
|
||||
else:
|
||||
oldpass = self.attr.getKey(prefix.nick, "password")
|
||||
if oldpass == 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 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])
|
||||
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.")
|
||||
cmd = self.bot.messageHasCommand(".setdogeaddr", trailing)
|
||||
if cmd:
|
||||
userpw = self.attr.getKey(prefix.nick, "password")
|
||||
if userpw==None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setdogeaddr: You must first set a password with .setpass")
|
||||
else:
|
||||
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])
|
||||
# if they don't have a wallet name, we'll make one now
|
||||
if self.attr.getKey(prefix.nick, "dogeaccountname")==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\"")
|
||||
|
||||
cmd = self.bot.messageHasCommand(".getdogebal", trailing)
|
||||
if cmd:
|
||||
userpw = self.attr.getKey(prefix.nick, "password")
|
||||
if userpw==None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getdogebal: You must first set a password with .setpass")
|
||||
else:
|
||||
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:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: You must first set a password with .setpass")
|
||||
elif useraddr==None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: You must first set a withdraw address .setdogeaddr")
|
||||
else:
|
||||
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))
|
||||
else:
|
||||
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))
|
||||
#################
|
||||
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\" - ")
|
||||
|
||||
cmd = self.bot.messageHasCommand(".getdepositaddr", trailing)
|
||||
if cmd:
|
||||
userpw = self.attr.getKey(prefix.nick, "password")
|
||||
if userpw==None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getdepositaddr: You must first set a password with .setpass")
|
||||
else:
|
||||
if len(cmd.args)==1:
|
||||
if userpw == cmd.args[0]:
|
||||
#################
|
||||
walletname = self.attr.getKey(prefix.nick, "dogeaccountname")
|
||||
addr = self.doge.getAcctAddr(walletname)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getdepositaddr: Your deposit address is: %s" % addr)
|
||||
#################
|
||||
else:
|
||||
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:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: You must first set a password with .setpass")
|
||||
else:
|
||||
if len(cmd.args)==1:
|
||||
if userpw == cmd.args[0]:
|
||||
#################
|
||||
self.attr.setKey(prefix.nick, "loggedinfrom", prefix.hostname)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: You have been logged in from: %s" % prefix.hostname)
|
||||
#################
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: incorrect password.")
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: usage: \".login password\"")
|
||||
cmd = self.bot.messageHasCommand(".logout", trailing)
|
||||
if cmd:
|
||||
loggedin = self.attr.getKey(prefix.nick, "loggedinfrom")
|
||||
if loggedin == 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"))
|
||||
return m.hexdigest()
|
||||
def __init__(self, bot, moduleName):
|
||||
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] == "#":
|
||||
# Ignore channel messages
|
||||
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\"")
|
||||
else:
|
||||
oldpass = self.attr.getKey(prefix.nick, "password")
|
||||
if oldpass == 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 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])
|
||||
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.")
|
||||
cmd = self.bot.messageHasCommand(".setdogeaddr", trailing)
|
||||
if cmd:
|
||||
userpw = self.attr.getKey(prefix.nick, "password")
|
||||
if userpw==None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setdogeaddr: You must first set a password with .setpass")
|
||||
else:
|
||||
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])
|
||||
# if they don't have a wallet name, we'll make one now
|
||||
if self.attr.getKey(prefix.nick, "dogeaccountname")==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\"")
|
||||
|
||||
cmd = self.bot.messageHasCommand(".getdogebal", trailing)
|
||||
if cmd:
|
||||
userpw = self.attr.getKey(prefix.nick, "password")
|
||||
if userpw==None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getdogebal: You must first set a password with .setpass")
|
||||
else:
|
||||
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:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: You must first set a password with .setpass")
|
||||
elif useraddr==None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: You must first set a withdraw address .setdogeaddr")
|
||||
else:
|
||||
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))
|
||||
else:
|
||||
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))
|
||||
#################
|
||||
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\" - ")
|
||||
|
||||
cmd = self.bot.messageHasCommand(".getdepositaddr", trailing)
|
||||
if cmd:
|
||||
userpw = self.attr.getKey(prefix.nick, "password")
|
||||
if userpw==None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getdepositaddr: You must first set a password with .setpass")
|
||||
else:
|
||||
if len(cmd.args)==1:
|
||||
if userpw == cmd.args[0]:
|
||||
#################
|
||||
walletname = self.attr.getKey(prefix.nick, "dogeaccountname")
|
||||
addr = self.doge.getAcctAddr(walletname)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getdepositaddr: Your deposit address is: %s" % addr)
|
||||
#################
|
||||
else:
|
||||
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:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: You must first set a password with .setpass")
|
||||
else:
|
||||
if len(cmd.args)==1:
|
||||
if userpw == cmd.args[0]:
|
||||
#################
|
||||
self.attr.setKey(prefix.nick, "loggedinfrom", prefix.hostname)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: You have been logged in from: %s" % prefix.hostname)
|
||||
#################
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: incorrect password.")
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: usage: \".login password\"")
|
||||
cmd = self.bot.messageHasCommand(".logout", trailing)
|
||||
if cmd:
|
||||
loggedin = self.attr.getKey(prefix.nick, "loggedinfrom")
|
||||
if loggedin == 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"))
|
||||
return m.hexdigest()
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""
|
||||
.. module:: Error
|
||||
:synopsis: Module to deliberately cause an error for testing handling.
|
||||
:synopsis: Module to deliberately cause an error for testing handling.
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -10,19 +10,19 @@
|
||||
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)]
|
||||
|
||||
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
|
||||
:type prefix: str
|
||||
:param trailing: IRC message body
|
||||
:type trailing: str"""
|
||||
if "error" in trailing:
|
||||
print(10/0)
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
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
|
||||
:type prefix: str
|
||||
:param trailing: IRC message body
|
||||
:type trailing: str"""
|
||||
if "error" in trailing:
|
||||
print(10/0)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: GameBase
|
||||
:synopsis: A codebase for making IRC games
|
||||
:synopsis: A codebase for making IRC games
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -14,59 +14,59 @@ import time
|
||||
from threading import Timer
|
||||
|
||||
class GameBase(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.gotMsg)]
|
||||
self.loadConfig()
|
||||
# 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?
|
||||
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])
|
||||
# Channel message
|
||||
self.games[args[0]].gotMsg(args, prefix, trailing)
|
||||
else:
|
||||
# Private message
|
||||
#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()
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.gotMsg)]
|
||||
self.loadConfig()
|
||||
# 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?
|
||||
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])
|
||||
# Channel message
|
||||
self.games[args[0]].gotMsg(args, prefix, trailing)
|
||||
else:
|
||||
# Private message
|
||||
#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"
|
||||
def gameover(self):
|
||||
pass
|
||||
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"
|
||||
def gameover(self):
|
||||
pass
|
||||
|
||||
class playerObj:
|
||||
def __init__(self, game, nick):
|
||||
self.game = game
|
||||
self.nick = nick
|
||||
|
||||
def __init__(self, game, nick):
|
||||
self.game = game
|
||||
self.nick = nick
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: Inventory
|
||||
:synopsis: Lets the bot hold random items
|
||||
:synopsis: Lets the bot hold random items
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -11,97 +11,97 @@ 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=[]
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
if len(serviceProviders)==0:
|
||||
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` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`date` INTEGER,
|
||||
`donor` varchar(64),
|
||||
`item` varchar(64)
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.checkInv)]
|
||||
|
||||
def checkInv(self, args, prefix, trailing):
|
||||
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:
|
||||
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,})
|
||||
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)})
|
||||
else:
|
||||
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!"})
|
||||
else:
|
||||
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,)) #
|
||||
row = c.fetchone()
|
||||
c.close()
|
||||
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:
|
||||
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()
|
||||
return dropped
|
||||
|
||||
def getinventory(self):
|
||||
inv = []
|
||||
c = self.db.query("SELECT * FROM `inventory`")
|
||||
while True:
|
||||
row = c.fetchone()
|
||||
if row == None:
|
||||
break
|
||||
inv.append(row["item"])
|
||||
c.close()
|
||||
return inv
|
||||
|
||||
def ondisable(self):
|
||||
self.db.close()
|
||||
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
if len(serviceProviders)==0:
|
||||
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` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`date` INTEGER,
|
||||
`donor` varchar(64),
|
||||
`item` varchar(64)
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.checkInv)]
|
||||
|
||||
def checkInv(self, args, prefix, trailing):
|
||||
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:
|
||||
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,})
|
||||
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)})
|
||||
else:
|
||||
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!"})
|
||||
else:
|
||||
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,)) #
|
||||
row = c.fetchone()
|
||||
c.close()
|
||||
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:
|
||||
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()
|
||||
return dropped
|
||||
|
||||
def getinventory(self):
|
||||
inv = []
|
||||
c = self.db.query("SELECT * FROM `inventory`")
|
||||
while True:
|
||||
row = c.fetchone()
|
||||
if row == None:
|
||||
break
|
||||
inv.append(row["item"])
|
||||
c.close()
|
||||
return inv
|
||||
|
||||
def ondisable(self):
|
||||
self.db.close()
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
"""
|
||||
.. module::LMGTFY
|
||||
:synopsis: LMGTFY
|
||||
:synopsis: LMGTFY
|
||||
.. moduleauthor::Nick Krichevsky <nick@ollien.com>
|
||||
"""
|
||||
|
||||
@ -12,27 +12,27 @@ 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)
|
||||
self.hooks.append(ModuleHook("PRIVMSG", self.handleMessage))
|
||||
self.bot = bot
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks.append(ModuleHook("PRIVMSG", self.handleMessage))
|
||||
self.bot = bot
|
||||
|
||||
def handleMessage(self, args, prefix, trailing):
|
||||
channel = args[0]
|
||||
prefix = self.bot.decodePrefix(prefix)
|
||||
if self.bot.messageHasCommand(".lmgtfy", trailing):
|
||||
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:
|
||||
message = message.split(" ")
|
||||
def handleMessage(self, args, prefix, trailing):
|
||||
channel = args[0]
|
||||
prefix = self.bot.decodePrefix(prefix)
|
||||
if self.bot.messageHasCommand(".lmgtfy", trailing):
|
||||
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:
|
||||
message = message.split(" ")
|
||||
|
||||
for word in message:
|
||||
finalUrl += urllib.parse.quote(word)
|
||||
if word != message[-1]:
|
||||
finalUrl+="+"
|
||||
for word in message:
|
||||
finalUrl += urllib.parse.quote(word)
|
||||
if word != message[-1]:
|
||||
finalUrl+="+"
|
||||
|
||||
return finalUrl
|
||||
return finalUrl
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: MySQL
|
||||
:synopsis: Module providing a mysql type service
|
||||
:synopsis: Module providing a mysql type service
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -11,108 +11,108 @@ from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
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()
|
||||
self.connection = self.getConnection()
|
||||
|
||||
def getConnection(self):
|
||||
return Connection(self)
|
||||
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.services=["mysql"]
|
||||
self.loadConfig()
|
||||
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;
|
||||
key = list(tables[0].keys())[0]
|
||||
for table in tables:
|
||||
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:
|
||||
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):
|
||||
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()
|
||||
except:
|
||||
try:
|
||||
self.connection.close()
|
||||
except:
|
||||
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.log.info("MySQL: Connected.")
|
||||
self.connection.autocommit(True)
|
||||
c = None
|
||||
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"]:
|
||||
found = True
|
||||
if not found:
|
||||
c.execute("CREATE DATABASE `%s`;" % self.config["database"])
|
||||
c.execute("USE `%s`;" % self.config["database"])
|
||||
c.close()
|
||||
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;
|
||||
key = list(tables[0].keys())[0]
|
||||
for table in tables:
|
||||
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:
|
||||
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):
|
||||
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()
|
||||
except:
|
||||
try:
|
||||
self.connection.close()
|
||||
except:
|
||||
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.log.info("MySQL: Connected.")
|
||||
self.connection.autocommit(True)
|
||||
c = None
|
||||
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"]:
|
||||
found = True
|
||||
if not found:
|
||||
c.execute("CREATE DATABASE `%s`;" % self.config["database"])
|
||||
c.execute("USE `%s`;" % self.config["database"])
|
||||
c.close()
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""
|
||||
.. module:: NFLLive
|
||||
:synopsis: Show upcoming NFL games and current scores.
|
||||
:synopsis: Show upcoming NFL games and current scores.
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -13,213 +13,213 @@ from lxml import etree
|
||||
from datetime import datetime,timedelta
|
||||
|
||||
class NFLLive(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.cache = None
|
||||
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]
|
||||
|
||||
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:
|
||||
liveGames.append(game)
|
||||
elif game["quarter"]=="P" and game["startdate"].day==datetime.now().day:
|
||||
gamesLaterToday.append(game)
|
||||
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 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":
|
||||
if not liveGamesStr == "":
|
||||
msgPieces.append("\x02Playing now:\x02 %s" % liveGamesStr)
|
||||
elif len(cmd.args)>0 and cmd.args[0]=="scores":
|
||||
if not liveGamesStr == "":
|
||||
msgPieces.append("\x02Playing now:\x02 %s" % liveGamesStr)
|
||||
if not gamesTodayStr == "":
|
||||
msgPieces.append("\x02Earlier today:\x02 %s" % gamesTodayStr)
|
||||
if not gamesEarlierWeekStr == "":
|
||||
msgPieces.append("\x02Earlier this week: \x02 %s" % gamesEarlierWeekStr)
|
||||
else:
|
||||
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)
|
||||
if not gamesEarlierWeekStr == "":
|
||||
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:
|
||||
msg = "No games!"
|
||||
|
||||
if len(msg)>0:
|
||||
# The message can be long so chunk it into pieces splitting at commas
|
||||
while len(msg)>0:
|
||||
piece = msg[0:330]
|
||||
msg = msg[330:]
|
||||
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"],
|
||||
game["visitor_score"],
|
||||
c_home,
|
||||
game["home"],
|
||||
game["home_score"],
|
||||
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"],
|
||||
game["visitor_score"],
|
||||
c_home,
|
||||
game["home"],
|
||||
game["home_score"]
|
||||
)
|
||||
|
||||
def getNflGamesCached(self):
|
||||
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["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.
|
||||
}
|
||||
|
||||
# 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["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":
|
||||
return "Regular"
|
||||
if season=="P":
|
||||
return "Pre"
|
||||
return season
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.cache = None
|
||||
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]
|
||||
|
||||
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:
|
||||
liveGames.append(game)
|
||||
elif game["quarter"]=="P" and game["startdate"].day==datetime.now().day:
|
||||
gamesLaterToday.append(game)
|
||||
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 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":
|
||||
if not liveGamesStr == "":
|
||||
msgPieces.append("\x02Playing now:\x02 %s" % liveGamesStr)
|
||||
elif len(cmd.args)>0 and cmd.args[0]=="scores":
|
||||
if not liveGamesStr == "":
|
||||
msgPieces.append("\x02Playing now:\x02 %s" % liveGamesStr)
|
||||
if not gamesTodayStr == "":
|
||||
msgPieces.append("\x02Earlier today:\x02 %s" % gamesTodayStr)
|
||||
if not gamesEarlierWeekStr == "":
|
||||
msgPieces.append("\x02Earlier this week: \x02 %s" % gamesEarlierWeekStr)
|
||||
else:
|
||||
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)
|
||||
if not gamesEarlierWeekStr == "":
|
||||
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:
|
||||
msg = "No games!"
|
||||
|
||||
if len(msg)>0:
|
||||
# The message can be long so chunk it into pieces splitting at commas
|
||||
while len(msg)>0:
|
||||
piece = msg[0:330]
|
||||
msg = msg[330:]
|
||||
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"],
|
||||
game["visitor_score"],
|
||||
c_home,
|
||||
game["home"],
|
||||
game["home_score"],
|
||||
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"],
|
||||
game["visitor_score"],
|
||||
c_home,
|
||||
game["home"],
|
||||
game["home_score"]
|
||||
)
|
||||
|
||||
def getNflGamesCached(self):
|
||||
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["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.
|
||||
}
|
||||
|
||||
# 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["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":
|
||||
return "Regular"
|
||||
if season=="P":
|
||||
return "Pre"
|
||||
return season
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: NickUser
|
||||
:synopsis: A module providing a simple login/logout account service
|
||||
:synopsis: A module providing a simple login/logout account service
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -12,80 +12,80 @@ import time
|
||||
import hashlib
|
||||
|
||||
class NickUser(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
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:
|
||||
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] == "#":
|
||||
# Ignore channel messages
|
||||
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\"")
|
||||
else:
|
||||
attr = self.bot.getBestModuleForService("attributes")
|
||||
oldpass = attr.getKey(prefix.nick, "password")
|
||||
if oldpass == 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 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])
|
||||
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.")
|
||||
|
||||
cmd = self.bot.messageHasCommand(".login", trailing)
|
||||
if cmd:
|
||||
attr = self.bot.getBestModuleForService("attributes")
|
||||
userpw = attr.getKey(prefix.nick, "password")
|
||||
if userpw==None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: You must first set a password with .setpass")
|
||||
else:
|
||||
if len(cmd.args)==1:
|
||||
if userpw == cmd.args[0]:
|
||||
#################
|
||||
attr.setKey(prefix.nick, "loggedinfrom", prefix.hostname)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: You have been logged in from: %s" % prefix.hostname)
|
||||
#################
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: incorrect password.")
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: usage: \".login password\"")
|
||||
cmd = self.bot.messageHasCommand(".logout", trailing)
|
||||
if cmd:
|
||||
attr = self.bot.getBestModuleForService("attributes")
|
||||
loggedin = attr.getKey(prefix.nick, "loggedinfrom")
|
||||
if loggedin == 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"))
|
||||
return m.hexdigest()
|
||||
def __init__(self, bot, moduleName):
|
||||
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:
|
||||
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] == "#":
|
||||
# Ignore channel messages
|
||||
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\"")
|
||||
else:
|
||||
attr = self.bot.getBestModuleForService("attributes")
|
||||
oldpass = attr.getKey(prefix.nick, "password")
|
||||
if oldpass == 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 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])
|
||||
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.")
|
||||
|
||||
cmd = self.bot.messageHasCommand(".login", trailing)
|
||||
if cmd:
|
||||
attr = self.bot.getBestModuleForService("attributes")
|
||||
userpw = attr.getKey(prefix.nick, "password")
|
||||
if userpw==None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: You must first set a password with .setpass")
|
||||
else:
|
||||
if len(cmd.args)==1:
|
||||
if userpw == cmd.args[0]:
|
||||
#################
|
||||
attr.setKey(prefix.nick, "loggedinfrom", prefix.hostname)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: You have been logged in from: %s" % prefix.hostname)
|
||||
#################
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: incorrect password.")
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: usage: \".login password\"")
|
||||
cmd = self.bot.messageHasCommand(".logout", trailing)
|
||||
if cmd:
|
||||
attr = self.bot.getBestModuleForService("attributes")
|
||||
loggedin = attr.getKey(prefix.nick, "loggedinfrom")
|
||||
if loggedin == 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"))
|
||||
return m.hexdigest()
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: PingResponder
|
||||
:synopsis: Module to repsond to irc server PING requests
|
||||
:synopsis: Module to repsond to irc server PING requests
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -10,11 +10,11 @@
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
|
||||
class PingResponder(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PING", self.pingrespond)]
|
||||
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 __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PING", self.pingrespond)]
|
||||
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))
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: RandQuote
|
||||
:synopsis: Log a configurable number of messages and pull up random ones on command
|
||||
:synopsis: Log a configurable number of messages and pull up random ones on command
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -11,57 +11,57 @@ 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=[]
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
if len(serviceProviders)==0:
|
||||
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` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`date` INTEGER,
|
||||
`sender` varchar(64),
|
||||
`message` varchar(2048)
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.logquote),ModuleHook("PRIVMSG", self.fetchquotes)]
|
||||
|
||||
def fetchquotes(self, args, prefix, trailing):
|
||||
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;")
|
||||
row = c.fetchone()
|
||||
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]=="#":
|
||||
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 = []
|
||||
c = self.db.query("SELECT * FROM `chat` ORDER BY `date` DESC LIMIT %s, 1000000;" % self.config["limit"])
|
||||
while True:
|
||||
row = c.fetchone()
|
||||
if not row:
|
||||
break
|
||||
self.db.query("DELETE FROM `chat` WHERE id=?", (row["id"],)).close()
|
||||
c.close()
|
||||
|
||||
def ondisable(self):
|
||||
self.db.close()
|
||||
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
if len(serviceProviders)==0:
|
||||
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` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`date` INTEGER,
|
||||
`sender` varchar(64),
|
||||
`message` varchar(2048)
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.logquote),ModuleHook("PRIVMSG", self.fetchquotes)]
|
||||
|
||||
def fetchquotes(self, args, prefix, trailing):
|
||||
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;")
|
||||
row = c.fetchone()
|
||||
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]=="#":
|
||||
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 = []
|
||||
c = self.db.query("SELECT * FROM `chat` ORDER BY `date` DESC LIMIT %s, 1000000;" % self.config["limit"])
|
||||
while True:
|
||||
row = c.fetchone()
|
||||
if not row:
|
||||
break
|
||||
self.db.query("DELETE FROM `chat` WHERE id=?", (row["id"],)).close()
|
||||
c.close()
|
||||
|
||||
def ondisable(self):
|
||||
self.db.close()
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""
|
||||
.. module:: Remind
|
||||
:synopsis: A module to support reminders
|
||||
:synopsis: A module to support reminders
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -14,262 +14,262 @@ import re
|
||||
import pytz
|
||||
|
||||
class Remind(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
if len(serviceProviders)==0:
|
||||
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` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`sender` varchar(64),
|
||||
`senderch` varchar(64),
|
||||
`when` timestamp,
|
||||
`message` varchar(2048)
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
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.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"]].append(reminder)
|
||||
|
||||
reminders_bych = {}
|
||||
|
||||
for recip in byrecip:
|
||||
reminders_pm = []
|
||||
|
||||
for reminder in byrecip[recip]:
|
||||
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"]].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:
|
||||
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]
|
||||
|
||||
# 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:
|
||||
second = int(second)
|
||||
|
||||
except:
|
||||
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:
|
||||
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
|
||||
remindAt = remindAt.replace(hour=hour).replace(minute=minute).replace(microsecond=0)
|
||||
|
||||
# Set seconds
|
||||
if second == 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:
|
||||
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:
|
||||
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))
|
||||
|
||||
# Save the reminder
|
||||
c = self.db.query("INSERT INTO `reminders` (`sender`, `senderch`, `when`, `message`) VALUES (?, ?, ?, ?)", (
|
||||
prefixObj.nick,
|
||||
args[0] if "#" in args[0] else "",
|
||||
remindAt,
|
||||
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))
|
||||
|
||||
@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"
|
||||
}
|
||||
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]
|
||||
|
||||
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))
|
||||
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))
|
||||
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]))
|
||||
return
|
||||
|
||||
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))
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
if len(serviceProviders)==0:
|
||||
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` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`sender` varchar(64),
|
||||
`senderch` varchar(64),
|
||||
`when` timestamp,
|
||||
`message` varchar(2048)
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
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.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"]].append(reminder)
|
||||
|
||||
reminders_bych = {}
|
||||
|
||||
for recip in byrecip:
|
||||
reminders_pm = []
|
||||
|
||||
for reminder in byrecip[recip]:
|
||||
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"]].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:
|
||||
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]
|
||||
|
||||
# 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:
|
||||
second = int(second)
|
||||
|
||||
except:
|
||||
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:
|
||||
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
|
||||
remindAt = remindAt.replace(hour=hour).replace(minute=minute).replace(microsecond=0)
|
||||
|
||||
# Set seconds
|
||||
if second == 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:
|
||||
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:
|
||||
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))
|
||||
|
||||
# Save the reminder
|
||||
c = self.db.query("INSERT INTO `reminders` (`sender`, `senderch`, `when`, `message`) VALUES (?, ?, ?, ?)", (
|
||||
prefixObj.nick,
|
||||
args[0] if "#" in args[0] else "",
|
||||
remindAt,
|
||||
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))
|
||||
|
||||
@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"
|
||||
}
|
||||
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]
|
||||
|
||||
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))
|
||||
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))
|
||||
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]))
|
||||
return
|
||||
|
||||
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))
|
||||
|
||||
scaling = {
|
||||
"years": 365.25 * 24 * 3600,
|
||||
"year": 365.25 * 24 * 3600,
|
||||
"yrs": 365.25 * 24 * 3600,
|
||||
"y": 365.25 * 24 * 3600,
|
||||
"months": 29.53059 * 24 * 3600,
|
||||
"month": 29.53059 * 24 * 3600,
|
||||
"mo": 29.53059 * 24 * 3600,
|
||||
"weeks": 7 * 24 * 3600,
|
||||
"week": 7 * 24 * 3600,
|
||||
"wks": 7 * 24 * 3600,
|
||||
"wk": 7 * 24 * 3600,
|
||||
"w": 7 * 24 * 3600,
|
||||
"days": 24 * 3600,
|
||||
"day": 24 * 3600,
|
||||
"d": 24 * 3600,
|
||||
"hours": 3600,
|
||||
"hour": 3600,
|
||||
"hrs": 3600,
|
||||
"hr": 3600,
|
||||
"h": 3600,
|
||||
"minutes": 60,
|
||||
"minute": 60,
|
||||
"mins": 60,
|
||||
"min": 60,
|
||||
"m": 60,
|
||||
"seconds": 1,
|
||||
"second": 1,
|
||||
"secs": 1,
|
||||
"sec": 1,
|
||||
"s": 1,
|
||||
}
|
||||
scaling = {
|
||||
"years": 365.25 * 24 * 3600,
|
||||
"year": 365.25 * 24 * 3600,
|
||||
"yrs": 365.25 * 24 * 3600,
|
||||
"y": 365.25 * 24 * 3600,
|
||||
"months": 29.53059 * 24 * 3600,
|
||||
"month": 29.53059 * 24 * 3600,
|
||||
"mo": 29.53059 * 24 * 3600,
|
||||
"weeks": 7 * 24 * 3600,
|
||||
"week": 7 * 24 * 3600,
|
||||
"wks": 7 * 24 * 3600,
|
||||
"wk": 7 * 24 * 3600,
|
||||
"w": 7 * 24 * 3600,
|
||||
"days": 24 * 3600,
|
||||
"day": 24 * 3600,
|
||||
"d": 24 * 3600,
|
||||
"hours": 3600,
|
||||
"hour": 3600,
|
||||
"hrs": 3600,
|
||||
"hr": 3600,
|
||||
"h": 3600,
|
||||
"minutes": 60,
|
||||
"minute": 60,
|
||||
"mins": 60,
|
||||
"min": 60,
|
||||
"m": 60,
|
||||
"seconds": 1,
|
||||
"second": 1,
|
||||
"secs": 1,
|
||||
"sec": 1,
|
||||
"s": 1,
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: SQLite
|
||||
:synopsis: Module providing a sqlite type service
|
||||
:synopsis: Module providing a sqlite type service
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -12,78 +12,78 @@ import sys
|
||||
import sqlite3
|
||||
|
||||
class SQLite(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.services=["sqlite"]
|
||||
self.loadConfig()
|
||||
|
||||
def opendb(self, dbname):
|
||||
return Connection(self, dbname)
|
||||
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.services=["sqlite"]
|
||||
self.loadConfig()
|
||||
|
||||
def opendb(self, dbname):
|
||||
return Connection(self, dbname)
|
||||
|
||||
|
||||
class Connection:
|
||||
def __init__(self, master, dbname):
|
||||
self.master = master
|
||||
self.log = master.log
|
||||
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;
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def dict_factory(cursor, row):
|
||||
d = {}
|
||||
for idx, col in enumerate(cursor.description):
|
||||
d[col[0]] = row[idx]
|
||||
return d
|
||||
def __init__(self, master, dbname):
|
||||
self.master = master
|
||||
self.log = master.log
|
||||
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;
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def dict_factory(cursor, row):
|
||||
d = {}
|
||||
for idx, col in enumerate(cursor.description):
|
||||
d[col[0]] = row[idx]
|
||||
return d
|
||||
|
||||
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:
|
||||
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()
|
||||
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))
|
||||
self.connection = sqlite3.connect(self.master.getFilePath(self.dbname), check_same_thread=False)
|
||||
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")
|
||||
c.close()
|
||||
|
||||
def close(self):
|
||||
self.connection.close()
|
||||
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:
|
||||
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()
|
||||
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))
|
||||
self.connection = sqlite3.connect(self.master.getFilePath(self.dbname), check_same_thread=False)
|
||||
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")
|
||||
c.close()
|
||||
|
||||
def close(self):
|
||||
self.connection.close()
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: Seen
|
||||
:synopsis: Provides !seen <username>
|
||||
:synopsis: Provides !seen <username>
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -12,61 +12,61 @@ 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()
|
||||
# if the database doesnt exist, it will be created
|
||||
sql = self.getSql()
|
||||
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:
|
||||
self.log.info("Seen: Creating database")
|
||||
# if no, create it.
|
||||
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()
|
||||
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))
|
||||
sql.commit()
|
||||
if trailing.startswith(".seen"):
|
||||
cmdargs = trailing.split(" ");
|
||||
# query the DB for the user
|
||||
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"]));
|
||||
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.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
|
||||
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.lastSeen)]
|
||||
self.loadConfig()
|
||||
# if the database doesnt exist, it will be created
|
||||
sql = self.getSql()
|
||||
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:
|
||||
self.log.info("Seen: Creating database")
|
||||
# if no, create it.
|
||||
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()
|
||||
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))
|
||||
sql.commit()
|
||||
if trailing.startswith(".seen"):
|
||||
cmdargs = trailing.split(" ");
|
||||
# query the DB for the user
|
||||
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"]));
|
||||
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.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
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: Services
|
||||
:synopsis: Provides the ability to configure a nickname, password, channel auto-join
|
||||
:synopsis: Provides the ability to configure a nickname, password, channel auto-join
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -11,54 +11,54 @@ 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.loadConfig()
|
||||
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"])
|
||||
|
||||
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
|
||||
if self.current_nick >= len(self.config["user"]["nick"]):
|
||||
self.log.critical("Ran out of usernames while selecting backup username!")
|
||||
return
|
||||
self.bot.act_NICK(self.config["user"]["nick"][self.current_nick])
|
||||
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.loadConfig()
|
||||
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"])
|
||||
|
||||
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
|
||||
if self.current_nick >= len(self.config["user"]["nick"]):
|
||||
self.log.critical("Ran out of usernames while selecting backup username!")
|
||||
return
|
||||
self.bot.act_NICK(self.config["user"]["nick"][self.current_nick])
|
||||
|
||||
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"]})
|
||||
sleep(2)
|
||||
self.bot.act_NICK(self.config["user"]["nick"][0])
|
||||
self.do_initservices()
|
||||
|
||||
def invited(self, args, prefix, trailing):
|
||||
"""Hook responding to INVITE channel invitations"""
|
||||
if trailing.lower() in self.config["privatechannels"]["list"]:
|
||||
self.log.info("Invited to %s, joining" % trailing)
|
||||
self.bot.act_JOIN(trailing)
|
||||
|
||||
def do_initservices(self):
|
||||
"""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"]})
|
||||
|
||||
" join plain channels "
|
||||
for channel in self.config["channels"]:
|
||||
self.log.info("Joining %s" % channel)
|
||||
self.bot.act_JOIN(channel)
|
||||
|
||||
" 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})
|
||||
|
||||
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"]})
|
||||
sleep(2)
|
||||
self.bot.act_NICK(self.config["user"]["nick"][0])
|
||||
self.do_initservices()
|
||||
|
||||
def invited(self, args, prefix, trailing):
|
||||
"""Hook responding to INVITE channel invitations"""
|
||||
if trailing.lower() in self.config["privatechannels"]["list"]:
|
||||
self.log.info("Invited to %s, joining" % trailing)
|
||||
self.bot.act_JOIN(trailing)
|
||||
|
||||
def do_initservices(self):
|
||||
"""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"]})
|
||||
|
||||
" join plain channels "
|
||||
for channel in self.config["channels"]:
|
||||
self.log.info("Joining %s" % channel)
|
||||
self.bot.act_JOIN(channel)
|
||||
|
||||
" 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})
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""
|
||||
.. module:: Tell
|
||||
:synopsis: Deliver a message to a user when they're next seen
|
||||
:synopsis: Deliver a message to a user when they're next seen
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -11,186 +11,186 @@ import datetime
|
||||
from time import mktime
|
||||
|
||||
class Tell(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
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` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`sender` varchar(64),
|
||||
`channel` varchar(64),
|
||||
`when` INTEGER,
|
||||
`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=[
|
||||
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()
|
||||
c.close()
|
||||
for tell in tells:
|
||||
agostr = Tell.timesince(datetime.datetime.fromtimestamp(tell["when"]))
|
||||
recip = None
|
||||
if tell["channel"]=="":
|
||||
recip = prefix.nick
|
||||
else:
|
||||
recip = tell["channel"]
|
||||
self.bot.act_PRIVMSG(recip, "%s: %s said %s ago: %s" % (
|
||||
prefix.nick,
|
||||
tell["sender"],
|
||||
agostr,
|
||||
tell["message"]
|
||||
))
|
||||
# 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]
|
||||
|
||||
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)
|
||||
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)
|
||||
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.bot.act_PRIVMSG(replyTo, "%s: I'll pass that along." % prefixObj.nick)
|
||||
|
||||
# Copyright (c) Django Software Foundation and individual contributors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of Django nor the names of its contributors may be used
|
||||
# to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"AND
|
||||
#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
#DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
#ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
#(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
#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'))
|
||||
)
|
||||
|
||||
# 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
|
||||
if since <= 0:
|
||||
# d is in the future compared to now, stop processing.
|
||||
return u'0 ' + 'minutes'
|
||||
for i, (seconds, name) in enumerate(chunks):
|
||||
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]
|
||||
count2 = (since - (seconds * count)) // seconds2
|
||||
if count2 != 0:
|
||||
if count2 == 1:
|
||||
s += ', %d %s' % (count2, name2[0])
|
||||
else:
|
||||
s += ', %d %s' % (count2, name2[1])
|
||||
return s
|
||||
|
||||
@staticmethod
|
||||
def timeuntil(d, now=None):
|
||||
"""
|
||||
Like timesince, but returns a string measuring the time until
|
||||
the given time.
|
||||
"""
|
||||
if not now:
|
||||
now = datetime.datetime.now()
|
||||
return timesince(now, d)
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
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` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`sender` varchar(64),
|
||||
`channel` varchar(64),
|
||||
`when` INTEGER,
|
||||
`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=[
|
||||
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()
|
||||
c.close()
|
||||
for tell in tells:
|
||||
agostr = Tell.timesince(datetime.datetime.fromtimestamp(tell["when"]))
|
||||
recip = None
|
||||
if tell["channel"]=="":
|
||||
recip = prefix.nick
|
||||
else:
|
||||
recip = tell["channel"]
|
||||
self.bot.act_PRIVMSG(recip, "%s: %s said %s ago: %s" % (
|
||||
prefix.nick,
|
||||
tell["sender"],
|
||||
agostr,
|
||||
tell["message"]
|
||||
))
|
||||
# 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]
|
||||
|
||||
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)
|
||||
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)
|
||||
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.bot.act_PRIVMSG(replyTo, "%s: I'll pass that along." % prefixObj.nick)
|
||||
|
||||
# Copyright (c) Django Software Foundation and individual contributors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of Django nor the names of its contributors may be used
|
||||
# to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"AND
|
||||
#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
#DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
#ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
#(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
#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'))
|
||||
)
|
||||
|
||||
# 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
|
||||
if since <= 0:
|
||||
# d is in the future compared to now, stop processing.
|
||||
return u'0 ' + 'minutes'
|
||||
for i, (seconds, name) in enumerate(chunks):
|
||||
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]
|
||||
count2 = (since - (seconds * count)) // seconds2
|
||||
if count2 != 0:
|
||||
if count2 == 1:
|
||||
s += ', %d %s' % (count2, name2[0])
|
||||
else:
|
||||
s += ', %d %s' % (count2, name2[1])
|
||||
return s
|
||||
|
||||
@staticmethod
|
||||
def timeuntil(d, now=None):
|
||||
"""
|
||||
Like timesince, but returns a string measuring the time until
|
||||
the given time.
|
||||
"""
|
||||
if not now:
|
||||
now = datetime.datetime.now()
|
||||
return timesince(now, d)
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
"""
|
||||
.. module::TextCDC
|
||||
:synopsis: Text Chrisdotcode, right now.
|
||||
:synopsis: Text Chrisdotcode, right now.
|
||||
.. moduleauthor::Nick Krichevsky <nick@ollien.com>
|
||||
"""
|
||||
|
||||
@ -14,98 +14,98 @@ 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.prefixes = [person for person in self.config["people"]]
|
||||
self.bot = bot
|
||||
self.timer = None
|
||||
self.setupTimer()
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks.append(ModuleHook("PRIVMSG",self.handleMessage))
|
||||
self.loadConfig()
|
||||
self.prefixes = [person for person in self.config["people"]]
|
||||
self.bot = bot
|
||||
self.timer = None
|
||||
self.setupTimer()
|
||||
|
||||
def ondisable(self):
|
||||
if self.timer != None:
|
||||
self.timer.cancel()
|
||||
def ondisable(self):
|
||||
if self.timer != 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.")
|
||||
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.quit()
|
||||
self.bot.act_PRIVMSG(channel, "Message sent.")
|
||||
except Exception as e:
|
||||
self.bot.log.error(str(e))
|
||||
self.bot.act_PRIVMSG(channel, "An SMTP Error has Occured")
|
||||
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.")
|
||||
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.quit()
|
||||
self.bot.act_PRIVMSG(channel, "Message sent.")
|
||||
except Exception as e:
|
||||
self.bot.log.error(str(e))
|
||||
self.bot.act_PRIVMSG(channel, "An SMTP Error has Occured")
|
||||
|
||||
def setupIMAP(self):
|
||||
imapObj = None
|
||||
if self.config["account"]["imap"]["ssl"]:
|
||||
imapObj = imaplib.IMAP4_SSL(self.config["account"]["imap"]["host"], self.config["account"]["imap"]["port"])
|
||||
else:
|
||||
imapObj = imaplib.IMAP4(self.config["account"]["imap"]["host"], self.config["account"]["imap"]["port"])
|
||||
imapObj.login(self.config["account"]["auth"]["username"], self.config["account"]["auth"]["password"])
|
||||
resp = imapObj.select("INBOX")
|
||||
if resp[0] == "OK":
|
||||
return imapObj
|
||||
else:
|
||||
return None
|
||||
def setupIMAP(self):
|
||||
imapObj = None
|
||||
if self.config["account"]["imap"]["ssl"]:
|
||||
imapObj = imaplib.IMAP4_SSL(self.config["account"]["imap"]["host"], self.config["account"]["imap"]["port"])
|
||||
else:
|
||||
imapObj = imaplib.IMAP4(self.config["account"]["imap"]["host"], self.config["account"]["imap"]["port"])
|
||||
imapObj.login(self.config["account"]["auth"]["username"], self.config["account"]["auth"]["password"])
|
||||
resp = imapObj.select("INBOX")
|
||||
if resp[0] == "OK":
|
||||
return imapObj
|
||||
else:
|
||||
return None
|
||||
|
||||
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"])
|
||||
else:
|
||||
smtpObj = smtplib.SMTP_SSL(self.config["account"]["smtp"]["host"], self.config["account"]["smtp"]["port"])
|
||||
if self.config["account"]["smtp"]["authentication"]:
|
||||
resp = smtpObj.login(self.config["account"]["auth"]["username"], self.config["account"]["auth"]["password"])
|
||||
if resp[0] == 235:
|
||||
return smtpObj
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
resp = smtpObj.connect()
|
||||
if resp[0] == 220:
|
||||
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.start()
|
||||
|
||||
def checkMail(self, bot, people, channels, imapObj = None):
|
||||
try:
|
||||
if imapObj == None:
|
||||
imapObj = self.setupIMAP()
|
||||
for person in people:
|
||||
emailAddr = people[person]["email-addr"]
|
||||
result = imapObj.search(None, "(FROM \"%s\")" % emailAddr)
|
||||
if (result[0] == "OK"):
|
||||
messageIds = result[1][0].decode("utf-8")
|
||||
if len(messageIds) > 0:
|
||||
messageIds = messageIds.split(" ")
|
||||
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:
|
||||
bot.act_PRIVMSG(channel, "Message from %s: %s" % (person, messageText))
|
||||
imapObj.store(messageId, "+FLAGS", "\\Deleted")
|
||||
else:
|
||||
raise Exception("SMTP Error. Status was %s, expected OK" % message[0])
|
||||
imapObj.logout()
|
||||
self.setupTimer()
|
||||
except Exception as e:
|
||||
if imapObj != None:
|
||||
imapObj.logout()
|
||||
self.setupTimer()
|
||||
raise e
|
||||
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"])
|
||||
else:
|
||||
smtpObj = smtplib.SMTP_SSL(self.config["account"]["smtp"]["host"], self.config["account"]["smtp"]["port"])
|
||||
if self.config["account"]["smtp"]["authentication"]:
|
||||
resp = smtpObj.login(self.config["account"]["auth"]["username"], self.config["account"]["auth"]["password"])
|
||||
if resp[0] == 235:
|
||||
return smtpObj
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
resp = smtpObj.connect()
|
||||
if resp[0] == 220:
|
||||
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.start()
|
||||
|
||||
def checkMail(self, bot, people, channels, imapObj = None):
|
||||
try:
|
||||
if imapObj == None:
|
||||
imapObj = self.setupIMAP()
|
||||
for person in people:
|
||||
emailAddr = people[person]["email-addr"]
|
||||
result = imapObj.search(None, "(FROM \"%s\")" % emailAddr)
|
||||
if (result[0] == "OK"):
|
||||
messageIds = result[1][0].decode("utf-8")
|
||||
if len(messageIds) > 0:
|
||||
messageIds = messageIds.split(" ")
|
||||
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:
|
||||
bot.act_PRIVMSG(channel, "Message from %s: %s" % (person, messageText))
|
||||
imapObj.store(messageId, "+FLAGS", "\\Deleted")
|
||||
else:
|
||||
raise Exception("SMTP Error. Status was %s, expected OK" % message[0])
|
||||
imapObj.logout()
|
||||
self.setupTimer()
|
||||
except Exception as e:
|
||||
if imapObj != None:
|
||||
imapObj.logout()
|
||||
self.setupTimer()
|
||||
raise e
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: Urban
|
||||
:synopsis: Lookup from urban dictionary
|
||||
:synopsis: Lookup from urban dictionary
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -12,24 +12,24 @@ import json
|
||||
from requests import get
|
||||
|
||||
class Urban(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
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() =="":
|
||||
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"]
|
||||
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']))
|
||||
|
||||
def __init__(self, bot, moduleName):
|
||||
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() =="":
|
||||
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"]
|
||||
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']))
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
.. module:: Weather
|
||||
:synopsis: Fetch weather by location string
|
||||
:synopsis: Fetch weather by location string
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
@ -12,206 +12,206 @@ 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"]
|
||||
|
||||
self.login = self.bot.getBestModuleForService("login")
|
||||
try:
|
||||
assert not self.login == 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:
|
||||
self.log.error("Weather: An 'attributes' service is required")
|
||||
return
|
||||
|
||||
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:
|
||||
self.send_weather(replyTo, fromWho, cmd.args_str, hasUnit)
|
||||
return
|
||||
|
||||
weatherZip = self.attr.get(fromWho, "weather-zip")
|
||||
if weatherZip == 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")
|
||||
return
|
||||
|
||||
weatherLoc = cmd.args_str
|
||||
|
||||
try:
|
||||
result = self.getWeather(weatherLoc)
|
||||
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)))
|
||||
return
|
||||
except LocationException as le:
|
||||
self.bot.act_PRIVMSG(fromWho, "'%s': location not found" % weatherLoc)
|
||||
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:
|
||||
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]=="#":
|
||||
unit = None
|
||||
try:
|
||||
assert cmd.args[0].lower() in ['c', 'f']
|
||||
unit = cmd.args[0]
|
||||
except:
|
||||
pass
|
||||
|
||||
if unit == 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())
|
||||
|
||||
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)))
|
||||
except LocationException as le:
|
||||
self.bot.act_PRIVMSG(target, "'%s': location not found" % location)
|
||||
|
||||
def alternates_to_str(self, alternates):
|
||||
pieces = []
|
||||
for item in alternates:
|
||||
item_pieces = []
|
||||
for key in ["name", "state", "country_name"]:
|
||||
if key in item and len(item[key].strip()):
|
||||
item_pieces.append(item[key])
|
||||
pieces.append(', '.join(item_pieces))
|
||||
return ' -- '.join(pieces)
|
||||
|
||||
def getWeather(self, zipcode, unit=None):
|
||||
if unit==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()
|
||||
|
||||
if "results" in data["response"]:
|
||||
raise LocationNotSpecificException(data["response"]["results"])
|
||||
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"]
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
def shorten_windstr(self, windstr):
|
||||
if "gusting" in windstr:
|
||||
return "Gusting"
|
||||
if "calm" in windstr:
|
||||
return "Calm"
|
||||
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 "⛅️"
|
||||
elif "cloudy" in icon:
|
||||
return "☁️"
|
||||
elif "rain" in icon:
|
||||
return "💧"
|
||||
elif "clear" in icon:
|
||||
return "☀️"
|
||||
elif "snow" in icon:
|
||||
return "❄️"
|
||||
else:
|
||||
return "(%s)" % icon
|
||||
|
||||
def deg_to_arrow(self, deg):
|
||||
if deg > 335 or deg < 0:
|
||||
return "↑"
|
||||
elif deg > 292:
|
||||
return "⇖"
|
||||
elif deg > 247:
|
||||
return "←"
|
||||
elif deg > 202:
|
||||
return "⇙"
|
||||
elif deg > 157:
|
||||
return "↓"
|
||||
elif deg > 112:
|
||||
return "⇘"
|
||||
elif deg > 67:
|
||||
return "→"
|
||||
elif deg > 22:
|
||||
return "⇗"
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
|
||||
assert not "get an API key" in self.config["apikey"]
|
||||
|
||||
self.login = self.bot.getBestModuleForService("login")
|
||||
try:
|
||||
assert not self.login == 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:
|
||||
self.log.error("Weather: An 'attributes' service is required")
|
||||
return
|
||||
|
||||
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:
|
||||
self.send_weather(replyTo, fromWho, cmd.args_str, hasUnit)
|
||||
return
|
||||
|
||||
weatherZip = self.attr.get(fromWho, "weather-zip")
|
||||
if weatherZip == 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")
|
||||
return
|
||||
|
||||
weatherLoc = cmd.args_str
|
||||
|
||||
try:
|
||||
result = self.getWeather(weatherLoc)
|
||||
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)))
|
||||
return
|
||||
except LocationException as le:
|
||||
self.bot.act_PRIVMSG(fromWho, "'%s': location not found" % weatherLoc)
|
||||
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:
|
||||
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]=="#":
|
||||
unit = None
|
||||
try:
|
||||
assert cmd.args[0].lower() in ['c', 'f']
|
||||
unit = cmd.args[0]
|
||||
except:
|
||||
pass
|
||||
|
||||
if unit == 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())
|
||||
|
||||
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)))
|
||||
except LocationException as le:
|
||||
self.bot.act_PRIVMSG(target, "'%s': location not found" % location)
|
||||
|
||||
def alternates_to_str(self, alternates):
|
||||
pieces = []
|
||||
for item in alternates:
|
||||
item_pieces = []
|
||||
for key in ["name", "state", "country_name"]:
|
||||
if key in item and len(item[key].strip()):
|
||||
item_pieces.append(item[key])
|
||||
pieces.append(', '.join(item_pieces))
|
||||
return ' -- '.join(pieces)
|
||||
|
||||
def getWeather(self, zipcode, unit=None):
|
||||
if unit==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()
|
||||
|
||||
if "results" in data["response"]:
|
||||
raise LocationNotSpecificException(data["response"]["results"])
|
||||
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"]
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
def shorten_windstr(self, windstr):
|
||||
if "gusting" in windstr:
|
||||
return "Gusting"
|
||||
if "calm" in windstr:
|
||||
return "Calm"
|
||||
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 "⛅️"
|
||||
elif "cloudy" in icon:
|
||||
return "☁️"
|
||||
elif "rain" in icon:
|
||||
return "💧"
|
||||
elif "clear" in icon:
|
||||
return "☀️"
|
||||
elif "snow" in icon:
|
||||
return "❄️"
|
||||
else:
|
||||
return "(%s)" % icon
|
||||
|
||||
def deg_to_arrow(self, deg):
|
||||
if deg > 335 or deg < 0:
|
||||
return "↑"
|
||||
elif deg > 292:
|
||||
return "⇖"
|
||||
elif deg > 247:
|
||||
return "←"
|
||||
elif deg > 202:
|
||||
return "⇙"
|
||||
elif deg > 157:
|
||||
return "↓"
|
||||
elif deg > 112:
|
||||
return "⇘"
|
||||
elif deg > 67:
|
||||
return "→"
|
||||
elif deg > 22:
|
||||
return "⇗"
|
||||
|
||||
class LocationException(Exception):
|
||||
pass
|
||||
pass
|
||||
|
||||
class LocationNotSpecificException(LocationException):
|
||||
def __init__(self, alternates):
|
||||
self.alternates = alternates
|
||||
pass
|
||||
def __init__(self, alternates):
|
||||
self.alternates = alternates
|
||||
pass
|
@ -1,6 +1,6 @@
|
||||
"""
|
||||
.. module:: Modules
|
||||
:synopsis: Module containing the bot's modules
|
||||
:synopsis: Module containing the bot's modules
|
||||
|
||||
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
|
||||
|
||||
|
16
setup.py
16
setup.py
@ -4,11 +4,11 @@ from setuptools import setup
|
||||
__version__ = "4.0.0-r02"
|
||||
|
||||
setup(name='pyircbot',
|
||||
version='4.0.0-r02',
|
||||
description='A modular python irc bot',
|
||||
url='http://gitlab.xmopx.net/dave/pyircbot3/tree/master',
|
||||
author='dpedu',
|
||||
author_email='dave@davepedu.com',
|
||||
packages=['pyircbot', 'pyircbot.modules'],
|
||||
scripts=['bin/pyircbot'],
|
||||
zip_safe=False)
|
||||
version='4.0.0-r02',
|
||||
description='A modular python irc bot',
|
||||
url='http://gitlab.xmopx.net/dave/pyircbot3/tree/master',
|
||||
author='dpedu',
|
||||
author_email='dave@davepedu.com',
|
||||
packages=['pyircbot', 'pyircbot.modules'],
|
||||
scripts=['bin/pyircbot'],
|
||||
zip_safe=False)
|
||||
|
Loading…
x
Reference in New Issue
Block a user