mirror of
https://github.com/SpiceBot/SpiceBot.git
synced 2026-11-11 14:10:58 -05:00
commit
af391dbc26
@ -7,3 +7,4 @@ recursive-include tests *
|
||||
recursive-exclude * __pycache__
|
||||
recursive-exclude * *.py[co]
|
||||
recursive-include sopel_modules/SpiceBot_GifSearch/gifapi *
|
||||
recursive-include sopel_modules/SpiceBot_Configs/aiml *
|
||||
|
||||
243
sopel_modules/SpiceBot/AI.py
Normal file
243
sopel_modules/SpiceBot/AI.py
Normal file
@ -0,0 +1,243 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot AI system. Based On Chatty cathy
|
||||
"""
|
||||
|
||||
from sopel.tools import Identifier
|
||||
from sopel.config.types import StaticSection, ListAttribute, ValidatedAttribute
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import aiml
|
||||
|
||||
from .Database import db as botdb
|
||||
from .Config import config as botconfig
|
||||
|
||||
|
||||
class SpiceBot_AI_MainSection(StaticSection):
|
||||
extra = ListAttribute('extra')
|
||||
gender = ValidatedAttribute('gender', default='female')
|
||||
|
||||
|
||||
class SpiceBot_AI():
|
||||
|
||||
def __init__(self):
|
||||
self.setup_ai()
|
||||
self.braindirs = []
|
||||
self.dict = {
|
||||
"patterncounts": 0,
|
||||
"filecounts": 0,
|
||||
"sessioncache": {},
|
||||
"files": {}
|
||||
}
|
||||
# Load AIML kernel
|
||||
self.aiml_kernel = aiml.Kernel()
|
||||
|
||||
# aiml parser
|
||||
self.aiml_parser = aiml.AimlParser.create_parser()
|
||||
|
||||
# Don't warn for no matches
|
||||
self.aiml_kernel._verboseMode = False
|
||||
|
||||
# Learn responses
|
||||
self.load_saved_brain()
|
||||
self.load_brain()
|
||||
|
||||
# Load bot values
|
||||
self.load_bot_values()
|
||||
|
||||
def setup_ai(self):
|
||||
botconfig.define_section("SpiceBot_AI", SpiceBot_AI_MainSection, validate=False)
|
||||
botconfig.config.aibrain = os.path.join(botconfig.homedir, botconfig.config.core.basename + '.aibrain.brn')
|
||||
|
||||
def load_saved_brain(self):
|
||||
if os.path.isfile(botconfig.config.aibrain):
|
||||
self.aiml_kernel.bootstrap(brainFile=botconfig.config.aibrain)
|
||||
self.save_brain()
|
||||
|
||||
def load_brain(self):
|
||||
import sopel_modules
|
||||
braindirs = []
|
||||
for plugin_dir in set(sopel_modules.__path__):
|
||||
configsdir = os.path.join(plugin_dir, "SpiceBot_Configs")
|
||||
aimldir = os.path.join(configsdir, "aiml")
|
||||
braindirs.append(aimldir)
|
||||
|
||||
if len(botconfig.SpiceBot_AI.extra):
|
||||
for extrabraindir in botconfig.SpiceBot_AI.extra:
|
||||
braindirs.append(extrabraindir)
|
||||
|
||||
# learn directories
|
||||
self.learn(braindirs)
|
||||
self.save_brain()
|
||||
|
||||
def load_bot_values(self):
|
||||
|
||||
current_bot_db = botdb.get_bot_value('botai') or None
|
||||
if current_bot_db:
|
||||
for predicate in current_bot_db.keys():
|
||||
predval = current_bot_db[predicate]
|
||||
self.aiml_kernel.setBotPredicate(predicate, predval)
|
||||
|
||||
# sopel nick
|
||||
self.aiml_kernel.setBotPredicate("nick", botconfig.nick)
|
||||
|
||||
# gender
|
||||
self.aiml_kernel.setBotPredicate("gender", botconfig.SpiceBot_AI.gender.lower())
|
||||
if botconfig.SpiceBot_AI.gender.lower() not in ["male", "female"]:
|
||||
self.aiml_kernel.setBotPredicate("gendertype", "item")
|
||||
else:
|
||||
self.aiml_kernel.setBotPredicate("gendertype", botconfig.SpiceBot_AI.gender.lower())
|
||||
|
||||
def learn(self, braindirs):
|
||||
for braindir in braindirs:
|
||||
if braindir not in self.braindirs:
|
||||
self.braindirs.append(braindir)
|
||||
|
||||
# Count matches
|
||||
for pathname in os.listdir(braindir):
|
||||
self.dict["filecounts"] += 1
|
||||
aimlfile = os.path.join(braindir, pathname)
|
||||
data = open(aimlfile).read()
|
||||
count = data.count('pattern')
|
||||
count = count / 2
|
||||
self.dict["patterncounts"] += int(count)
|
||||
|
||||
tempbrain = tempfile.mkstemp()[1]
|
||||
with open(tempbrain, 'w') as fileo:
|
||||
fileo.write(
|
||||
"<aiml version='1.0.1' encoding='UTF-8'>"
|
||||
" <!-- std-startup.xml -->\n"
|
||||
" <category>\n"
|
||||
" <pattern>LOAD AIML B</pattern>\n"
|
||||
" <template>\n"
|
||||
" <learn>{}</learn>\n"
|
||||
" </template>\n"
|
||||
" </category>\n"
|
||||
"</aiml>".format(os.path.join(braindir, "*.aiml"))
|
||||
)
|
||||
self.aiml_kernel.learn(tempbrain)
|
||||
self.aiml_kernel.respond("LOAD AIML B")
|
||||
|
||||
def on_message(self, bot, trigger, message):
|
||||
|
||||
nick = Identifier(trigger.nick)
|
||||
nick_id = botdb.get_nick_id(nick, create=True)
|
||||
self.check_user_import(nick, nick_id)
|
||||
|
||||
message = self.bot_message_precipher(bot, trigger, message)
|
||||
aiml_response = self.aiml_kernel.respond(message, nick_id)
|
||||
if aiml_response:
|
||||
aiml_response = self.bot_message_decipher(bot, trigger, aiml_response)
|
||||
|
||||
self.save_nick_session(nick, nick_id)
|
||||
self.save_brain()
|
||||
|
||||
return aiml_response
|
||||
|
||||
def bot_message_precipher(self, bot, trigger, message):
|
||||
|
||||
# uppercase input
|
||||
message = message.upper()
|
||||
|
||||
# punctuation
|
||||
puct_dict = {"!": "exclamationmark", ".": "period", "?": "questionmark", ",": "comma"}
|
||||
for puctuation in puct_dict.keys():
|
||||
message = message.replace(puctuation, puct_dict[puctuation])
|
||||
|
||||
# bot items
|
||||
for botitem in ["nick"]:
|
||||
message = message.replace(str(eval("bot." + botitem)).upper(), str("bot" + botitem).upper())
|
||||
|
||||
for triggeritem in ["nick", "sender"]:
|
||||
message = message.replace(str(eval("trigger." + triggeritem)).upper(), str("trigger" + triggeritem).upper())
|
||||
|
||||
return message
|
||||
|
||||
def bot_message_decipher(self, bot, trigger, aiml_response):
|
||||
|
||||
# bot items
|
||||
for botitem in ["nick"]:
|
||||
aiml_response = aiml_response.replace("bot" + botitem, str(eval("bot." + botitem)))
|
||||
|
||||
# trigger items
|
||||
for triggeritem in ["nick", "sender"]:
|
||||
aiml_response = aiml_response.replace("trigger" + triggeritem, str(eval("trigger." + triggeritem)))
|
||||
|
||||
# pronouns
|
||||
botgendertype = self.aiml_kernel.getBotPredicate("gendertype")
|
||||
pronounsdict = {
|
||||
"male": {
|
||||
"main": "he",
|
||||
"possess": "his",
|
||||
"self": "himself",
|
||||
},
|
||||
"female": {
|
||||
"main": "her",
|
||||
"possess": "hers",
|
||||
"self": "herself",
|
||||
},
|
||||
"item": {
|
||||
"main": "it",
|
||||
"possess": "its",
|
||||
"self": "itself",
|
||||
},
|
||||
"point": {
|
||||
"main": "you",
|
||||
"possess": "yours",
|
||||
"self": "yourself",
|
||||
},
|
||||
"group": {
|
||||
"main": "them",
|
||||
"possess": "theirs",
|
||||
"self": "themselves",
|
||||
},
|
||||
}
|
||||
for pronounitem in pronounsdict[botgendertype].keys():
|
||||
aiml_response = aiml_response.replace("BOTPRONOUN" + pronounitem, pronounsdict[botgendertype][pronounitem])
|
||||
triggergendertype = self.getPredicate("gender", trigger.nick)
|
||||
if not triggergendertype or triggergendertype == "":
|
||||
triggergendertype = "point"
|
||||
for pronounitem in pronounsdict[triggergendertype].keys():
|
||||
aiml_response = aiml_response.replace("TRIGGERPRONOUN" + pronounitem, pronounsdict[triggergendertype][pronounitem])
|
||||
|
||||
aiml_response = "\x0315" + aiml_response + "\x03"
|
||||
|
||||
return aiml_response
|
||||
|
||||
def getPredicate(self, predicate, nick, nick_id=None):
|
||||
if not nick_id:
|
||||
nick = Identifier(nick)
|
||||
nick_id = botdb.get_nick_id(nick, create=True)
|
||||
self.aiml_kernel.getPredicate(predicate, nick_id)
|
||||
|
||||
def check_user_import(self, nick, nick_id=None):
|
||||
if not nick_id:
|
||||
nick = Identifier(nick)
|
||||
nick_id = botdb.get_nick_id(nick, create=True)
|
||||
if nick_id not in self.dict["sessioncache"].keys():
|
||||
self.dict["sessioncache"][nick_id] = botdb.get_nick_value(nick, 'botai') or {}
|
||||
for predicate in self.dict["sessioncache"][nick_id].keys():
|
||||
predval = self.dict["sessioncache"][nick_id][predicate]
|
||||
self.aiml_kernel.setPredicate(predicate, predval, nick_id)
|
||||
|
||||
# defaults
|
||||
if "nick" not in self.dict["sessioncache"][nick_id].keys():
|
||||
self.dict["sessioncache"][nick_id]["nick"] = nick
|
||||
self.aiml_kernel.setPredicate("nick", nick, nick_id)
|
||||
|
||||
def save_nick_session(self, nick, nick_id=None):
|
||||
if not nick_id:
|
||||
nick = Identifier(nick)
|
||||
nick_id = botdb.get_nick_id(nick, create=True)
|
||||
sessionData = self.aiml_kernel.getSessionData(nick_id)
|
||||
botdb.set_nick_value(nick, 'botai', sessionData)
|
||||
|
||||
def save_brain(self):
|
||||
self.aiml_kernel.saveBrain(botconfig.config.aibrain)
|
||||
botsessiondata = self.aiml_kernel._botPredicates
|
||||
botdb.set_bot_value('botai', botsessiondata)
|
||||
|
||||
|
||||
botai = SpiceBot_AI()
|
||||
@ -1,22 +1,38 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot Logs system.
|
||||
|
||||
This Class stores logs in an easy to access manner
|
||||
This is the SpiceBot Channels system.
|
||||
"""
|
||||
import sopel
|
||||
from sopel.config.types import StaticSection, ValidatedAttribute, ListAttribute
|
||||
|
||||
import re
|
||||
import threading
|
||||
|
||||
from .Config import config as botconfig
|
||||
|
||||
|
||||
class SpiceBot_Channels_MainSection(StaticSection):
|
||||
announcenew = ValidatedAttribute('announcenew', default=False)
|
||||
joinall = ValidatedAttribute('joinall', default=False)
|
||||
operadmin = ValidatedAttribute('operadmin', default=False)
|
||||
chanignore = ListAttribute('chanignore')
|
||||
|
||||
|
||||
class BotChannels():
|
||||
"""This Logs all channels known to the server"""
|
||||
def __init__(self):
|
||||
self.setup_channels()
|
||||
|
||||
self.lock = threading.Lock()
|
||||
self.channel_lock = False
|
||||
self.SpiceBot_Channels = {
|
||||
"list": {},
|
||||
"InitialProcess": False
|
||||
}
|
||||
self.dict = {
|
||||
"list": {},
|
||||
"InitialProcess": False
|
||||
}
|
||||
|
||||
def setup_channels(self):
|
||||
botconfig.define_section("SpiceBot_Channels", SpiceBot_Channels_MainSection, validate=False)
|
||||
|
||||
def channel_list_request(self, bot):
|
||||
bot.write(['LIST'])
|
||||
@ -25,16 +41,20 @@ class BotChannels():
|
||||
self.channel_lock = True
|
||||
|
||||
def channel_list_recieve_input(self, trigger):
|
||||
self.lock.acquire()
|
||||
channel, _, topic = trigger.args[1:]
|
||||
if channel.lower() not in self.SpiceBot_Channels['list'].keys():
|
||||
self.SpiceBot_Channels['list'][channel.lower()] = dict()
|
||||
self.SpiceBot_Channels['list'][channel.lower()]['name'] = channel
|
||||
self.SpiceBot_Channels['list'][channel.lower()]['topic'] = self.topic_compile(topic)
|
||||
if channel.lower() not in self.dict['list'].keys():
|
||||
self.dict['list'][channel.lower()] = dict()
|
||||
self.dict['list'][channel.lower()]['name'] = channel
|
||||
self.dict['list'][channel.lower()]['topic'] = self.topic_compile(topic)
|
||||
self.channel_lock = True
|
||||
self.lock.release()
|
||||
|
||||
def channel_list_recieve_finish(self):
|
||||
if not self.SpiceBot_Channels['InitialProcess']:
|
||||
self.SpiceBot_Channels['InitialProcess'] = True
|
||||
self.lock.acquire()
|
||||
if not self.dict['InitialProcess']:
|
||||
self.dict['InitialProcess'] = True
|
||||
self.lock.release()
|
||||
self.channel_lock = False
|
||||
|
||||
def topic_compile(self, topic):
|
||||
@ -50,28 +70,30 @@ class BotChannels():
|
||||
for channel in bot.channels.keys():
|
||||
if len(bot.channels[channel].privileges.keys()) == 1 and channel not in ignorepartlist and channel.startswith("#"):
|
||||
bot.part(channel, "Leaving Empty Channel")
|
||||
if channel.lower() in botchannels.SpiceBot_Channels['list']:
|
||||
del botchannels.SpiceBot_Channels['list'][channel.lower()]
|
||||
if channel.lower() in self.dict['list']:
|
||||
self.lock.acquire()
|
||||
del self.dict['list'][channel.lower()]
|
||||
self.lock.release()
|
||||
|
||||
def join_all_channels(self, bot):
|
||||
if bot.config.SpiceBot_Channels.joinall:
|
||||
for channel in botchannels.SpiceBot_Channels['list'].keys():
|
||||
if botconfig.SpiceBot_Channels.joinall:
|
||||
for channel in self.dict['list'].keys():
|
||||
if channel.startswith("#"):
|
||||
if channel not in bot.channels.keys() and channel not in bot.config.SpiceBot_Channels.chanignore:
|
||||
bot.write(('JOIN', bot.nick, botchannels.SpiceBot_Channels['list'][channel]['name']))
|
||||
if channel not in bot.channels.keys() and bot.config.SpiceBot_Channels.operadmin:
|
||||
bot.write(('SAJOIN', bot.nick, botchannels.SpiceBot_Channels['list'][channel]['name']))
|
||||
if channel not in bot.channels.keys() and channel not in botconfig.SpiceBot_Channels.chanignore:
|
||||
bot.write(('JOIN', bot.nick, self.dict['list'][channel]['name']))
|
||||
if channel not in bot.channels.keys() and botconfig.SpiceBot_Channels.operadmin:
|
||||
bot.write(('SAJOIN', bot.nick, self.dict['list'][channel]['name']))
|
||||
|
||||
def chanadmin_all_channels(self, bot):
|
||||
# Chan ADMIN +a
|
||||
for channel in bot.channels.keys():
|
||||
if channel.startswith("#"):
|
||||
if channel not in bot.config.SpiceBot_Channels.chanignore:
|
||||
if bot.config.SpiceBot_Channels.operadmin:
|
||||
if channel not in botconfig.SpiceBot_Channels.chanignore:
|
||||
if botconfig.SpiceBot_Channels.operadmin:
|
||||
if not bot.channels[channel].privileges[bot.nick] < sopel.module.ADMIN:
|
||||
bot.write(('SAMODE', channel, "+a", bot.nick))
|
||||
else:
|
||||
bot.part(channel)
|
||||
|
||||
|
||||
botchannels = BotChannels()
|
||||
channels = BotChannels()
|
||||
|
||||
259
sopel_modules/SpiceBot/Commands.py
Normal file
259
sopel_modules/SpiceBot/Commands.py
Normal file
@ -0,0 +1,259 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot Commands system.
|
||||
|
||||
This Class stores commands in an easy to access manner
|
||||
"""
|
||||
|
||||
import sopel
|
||||
from sopel.config.types import StaticSection, ValidatedAttribute
|
||||
|
||||
import os
|
||||
import threading
|
||||
|
||||
import spicemanip
|
||||
|
||||
from .Logs import logs
|
||||
from .Config import config as botconfig
|
||||
from .Database import db as botdb
|
||||
|
||||
|
||||
class SpiceBot_Commands_MainSection(StaticSection):
|
||||
query_prefix = ValidatedAttribute('query_prefix', default="?")
|
||||
|
||||
|
||||
class BotCommands():
|
||||
"""This Logs all commands known to the bot"""
|
||||
def __init__(self):
|
||||
self.setup_commands()
|
||||
self.lock = threading.Lock()
|
||||
self.dict = {
|
||||
"counts": 0,
|
||||
'nickrules': [],
|
||||
'nickaiml': [],
|
||||
"commands": {
|
||||
'module': {},
|
||||
'nickname': {},
|
||||
'rule': {}
|
||||
},
|
||||
'disabled': {}
|
||||
}
|
||||
self.module_files_parse()
|
||||
self.nickrules()
|
||||
for comtype in ['module', 'nickname', 'rule']:
|
||||
logs.log('SpiceBot_Commands', "Found " + str(len(self.dict['commands'][comtype].keys())) + " " + comtype + " commands.", True)
|
||||
|
||||
def setup_commands(self):
|
||||
botconfig.define_section("SpiceBot_Commands", SpiceBot_Commands_MainSection, validate=False)
|
||||
botconfig.core.query_list = str(botconfig.SpiceBot_Commands.query_prefix).replace("\\", '').split("|")
|
||||
botconfig.core.prefix_list.extend(botconfig.SpiceBot_Commands.query_prefix)
|
||||
|
||||
def nickrules(self):
|
||||
for command in self.dict['commands']['rule'].keys():
|
||||
if command.startswith("$nickname"):
|
||||
command = command.split("$nickname")[-1]
|
||||
if command not in self.dict['nickrules']:
|
||||
self.dict['nickrules'].append(command)
|
||||
|
||||
def find_command_type(self, command):
|
||||
for commandstype in self.dict['commands'].keys():
|
||||
if commandstype not in ['rule']:
|
||||
for com in self.dict['commands'][commandstype].keys():
|
||||
if com.lower() == command.lower():
|
||||
return commandstype
|
||||
return None
|
||||
|
||||
def get_commands_disabled(self, channel):
|
||||
if not len(list(self.dict['disabled'])):
|
||||
self.dict['disabled'] = botdb.get_channel_value(channel, 'commands_disabled') or {}
|
||||
return self.dict['disabled']
|
||||
|
||||
def check_commands_disabled(self, command, channel):
|
||||
if command in self.get_commands_disabled(channel).keys():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_realcom(self, command, trigger_command_type):
|
||||
realcom = command
|
||||
|
||||
if trigger_command_type not in self.dict['commands'].keys():
|
||||
return realcom
|
||||
|
||||
if command not in self.dict['commands'][trigger_command_type].keys():
|
||||
return realcom
|
||||
|
||||
if "aliasfor" in self.dict['commands'][trigger_command_type][command].keys():
|
||||
realcom = self.dict['commands'][trigger_command_type][command]
|
||||
|
||||
return realcom
|
||||
|
||||
def set_command_disabled(self, command, channel, timestamp, reason, bywhom):
|
||||
if not len(list(self.dict['disabled'])):
|
||||
self.dict['disabled'] = botdb.get_channel_value(channel, 'commands_disabled') or {}
|
||||
self.dict['disabled'][command] = {"reason": reason, "timestamp": timestamp, "disabledby": bywhom}
|
||||
botdb.set_channel_value(channel, 'commands_disabled', self.dict['disabled'])
|
||||
|
||||
def unset_command_disabled(self, command, channel):
|
||||
if not len(list(self.dict['disabled'])):
|
||||
self.dict['disabled'] = botdb.get_channel_value(channel, 'commands_disabled') or {}
|
||||
if command in self.dict['disabled'].keys():
|
||||
del self.dict['disabled'][command]
|
||||
botdb.set_channel_value(channel, 'commands_disabled', self.dict['disabled'])
|
||||
|
||||
def register(self, command_dict):
|
||||
|
||||
self.lock.acquire()
|
||||
|
||||
command_type = command_dict["comtype"]
|
||||
validcoms = command_dict["validcoms"]
|
||||
|
||||
if not isinstance(validcoms, list):
|
||||
validcoms = [validcoms]
|
||||
|
||||
if command_type not in self.dict['commands'].keys():
|
||||
self.dict['commands'][command_type] = dict()
|
||||
|
||||
dict_from_file = dict()
|
||||
|
||||
# default command to filename
|
||||
if "validcoms" not in dict_from_file.keys():
|
||||
dict_from_file["validcoms"] = validcoms
|
||||
|
||||
maincom = dict_from_file["validcoms"][0]
|
||||
if len(dict_from_file["validcoms"]) > 1:
|
||||
comaliases = spicemanip.main(dict_from_file["validcoms"], '2+', 'list')
|
||||
else:
|
||||
comaliases = []
|
||||
|
||||
self.dict['commands'][command_type][maincom] = dict_from_file
|
||||
for comalias in comaliases:
|
||||
if comalias not in self.dict['commands'][command_type].keys():
|
||||
self.dict['commands'][command_type][comalias] = {"aliasfor": maincom}
|
||||
|
||||
self.lock.release()
|
||||
|
||||
def module_directory_list(self):
|
||||
filepathlisting = []
|
||||
|
||||
# main Modules directory
|
||||
main_dir = os.path.dirname(os.path.abspath(sopel.__file__))
|
||||
modules_dir = os.path.join(main_dir, 'modules')
|
||||
filepathlisting.append(modules_dir)
|
||||
|
||||
# Home Directory
|
||||
home_modules_dir = os.path.join(botconfig.homedir, 'modules')
|
||||
if os.path.isdir(home_modules_dir):
|
||||
filepathlisting.append(home_modules_dir)
|
||||
|
||||
# pypi installed
|
||||
try:
|
||||
import sopel_modules
|
||||
for plugin_dir in set(sopel_modules.__path__):
|
||||
for pathname in os.listdir(plugin_dir):
|
||||
pypi_modules_dir = os.path.join(plugin_dir, pathname)
|
||||
filepathlisting.append(pypi_modules_dir)
|
||||
except Exception as e:
|
||||
logs.log('SpiceBOT_COMMANDS', "sopel_modules not loaded :" + str(e))
|
||||
|
||||
# Extra directories
|
||||
for directory in botconfig.extra:
|
||||
filepathlisting.append(directory)
|
||||
|
||||
return filepathlisting
|
||||
|
||||
def module_files_list(self):
|
||||
filepathlisting = self.module_directory_list()
|
||||
|
||||
filepathlist = []
|
||||
|
||||
for directory in filepathlisting:
|
||||
for pathname in os.listdir(directory):
|
||||
path = os.path.join(directory, pathname)
|
||||
if (os.path.isfile(path) and path.endswith('.py') and not path.startswith('_')):
|
||||
if pathname not in ["SpiceBot_dummycommand.py"]:
|
||||
filepathlist.append(str(path))
|
||||
|
||||
# CoreTasks
|
||||
main_dir = os.path.dirname(os.path.abspath(sopel.__file__))
|
||||
ct_path = os.path.join(main_dir, 'coretasks.py')
|
||||
filepathlist.append(ct_path)
|
||||
|
||||
return filepathlist
|
||||
|
||||
def module_files_parse(self):
|
||||
filepathlist = self.module_files_list()
|
||||
|
||||
for modulefile in filepathlist:
|
||||
|
||||
module_file_lines = []
|
||||
module_file = open(modulefile, 'r')
|
||||
lines = module_file.readlines()
|
||||
for line in lines:
|
||||
module_file_lines.append(line)
|
||||
module_file.close()
|
||||
|
||||
detected_lines = []
|
||||
for line in module_file_lines:
|
||||
|
||||
if str(line).startswith("@"):
|
||||
line = str(line)[1:]
|
||||
|
||||
if str(line).startswith(tuple(["commands", "module.commands", "sopel.module.commands"])):
|
||||
line = str(line).split("commands")[-1]
|
||||
line = "commands" + line
|
||||
detected_lines.append(line)
|
||||
elif str(line).startswith(tuple(["nickname_commands", "module.nickname_commands", "sopel.module.nickname_commands"])):
|
||||
line = str(line).split("nickname_commands")[-1]
|
||||
line = "nickname_commands" + line
|
||||
detected_lines.append(line)
|
||||
elif str(line).startswith(tuple(["rule", "module.rule", "sopel.module.rule"])):
|
||||
line = str(line).split("rule")[-1]
|
||||
line = "rule" + line
|
||||
else:
|
||||
line = None
|
||||
|
||||
if line:
|
||||
detected_lines.append(line)
|
||||
|
||||
if len(detected_lines):
|
||||
|
||||
filelinelist = []
|
||||
currentsuccesslines = 0
|
||||
for detected_line in detected_lines:
|
||||
|
||||
# Commands
|
||||
if str(detected_line).startswith("commands"):
|
||||
comtype = "module"
|
||||
validcoms = eval(str(detected_line).split("commands")[-1])
|
||||
elif str(detected_line).startswith("nickname_commands"):
|
||||
comtype = "nickname"
|
||||
validcoms = eval(str(detected_line).split("nickname_commands")[-1])
|
||||
elif str(detected_line).startswith("rule"):
|
||||
comtype = "rule"
|
||||
validcoms = eval(str(detected_line).split("rule")[-1])
|
||||
|
||||
if isinstance(validcoms, tuple):
|
||||
validcoms = list(validcoms)
|
||||
else:
|
||||
validcoms = [validcoms]
|
||||
for regexcom in ["(.*)", '^\?(.*)']:
|
||||
if regexcom in validcoms:
|
||||
while regexcom in validcoms:
|
||||
validcoms.remove(regexcom)
|
||||
|
||||
if len(validcoms):
|
||||
validcomdict = {"comtype": comtype, "validcoms": validcoms}
|
||||
filelinelist.append(validcomdict)
|
||||
currentsuccesslines += 1
|
||||
|
||||
if currentsuccesslines:
|
||||
self.dict['counts'] += 1
|
||||
|
||||
if len(filelinelist):
|
||||
for atlinefound in filelinelist:
|
||||
self.register(atlinefound)
|
||||
|
||||
|
||||
commands = BotCommands()
|
||||
57
sopel_modules/SpiceBot/Config.py
Normal file
57
sopel_modules/SpiceBot/Config.py
Normal file
@ -0,0 +1,57 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""A way to read the bot's config without bot"""
|
||||
|
||||
from sopel.cli.run import build_parser, get_configuration
|
||||
|
||||
import sys
|
||||
import os
|
||||
import configparser
|
||||
|
||||
|
||||
class BotConfig():
|
||||
|
||||
def __init__(self):
|
||||
self.dict = {}
|
||||
# Load config
|
||||
parser = build_parser()
|
||||
if not len(sys.argv[1:]):
|
||||
argv = ['legacy']
|
||||
else:
|
||||
argv = sys.argv[1:]
|
||||
opts = parser.parse_args(argv)
|
||||
self.config = get_configuration(opts)
|
||||
|
||||
self.setup_config()
|
||||
|
||||
# load as dict
|
||||
config = configparser.ConfigParser()
|
||||
config.read(self.config.filename)
|
||||
for each_section in config.sections():
|
||||
if each_section.lower() not in self.dict.keys():
|
||||
self.dict[each_section.lower()] = dict()
|
||||
for (each_key, each_val) in config.items(each_section):
|
||||
if each_key.lower() not in self.dict[each_section.lower()].keys():
|
||||
self.dict[each_section.lower()][each_key.lower()] = each_val
|
||||
|
||||
def setup_config(self):
|
||||
self.config.core.basename = os.path.basename(self.config.filename).rsplit('.', 1)[0]
|
||||
self.config.core.prefix_list = str(self.config.core.prefix).replace("\\", '').split("|")
|
||||
|
||||
def define_section(self, name, cls_, validate=True):
|
||||
return self.config.define_section(name, cls_, validate)
|
||||
|
||||
def __getattr__(self, name):
|
||||
''' will only get called for undefined attributes '''
|
||||
"""We will try to find a core value, or return None"""
|
||||
if hasattr(self.config.core, name):
|
||||
return eval("self.config.core." + name)
|
||||
elif name.lower() in self.dict["core"].keys():
|
||||
return self.dict["core"][str(name).lower()]
|
||||
elif hasattr(self.config, name):
|
||||
return eval("self.config." + name)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
config = BotConfig()
|
||||
595
sopel_modules/SpiceBot/Database.py
Normal file
595
sopel_modules/SpiceBot/Database.py
Normal file
@ -0,0 +1,595 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot Database
|
||||
"""
|
||||
|
||||
# sopel imports
|
||||
from sopel.tools import Identifier
|
||||
import sopel.db
|
||||
from sopel.db import SopelDB, _deserialize
|
||||
|
||||
from .Config import config as botconfig
|
||||
|
||||
from sqlalchemy import Column, String, ForeignKey, Integer, Text
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
import json
|
||||
|
||||
|
||||
BASE = declarative_base()
|
||||
|
||||
|
||||
class NickIDs(BASE):
|
||||
"""
|
||||
NickIDs SQLAlchemy Class
|
||||
"""
|
||||
__tablename__ = 'nick_ids'
|
||||
nick_id = Column(Integer, primary_key=True)
|
||||
|
||||
|
||||
class Nicknames(BASE):
|
||||
"""
|
||||
Nicknames SQLAlchemy Class
|
||||
"""
|
||||
__tablename__ = 'nicknames'
|
||||
nick_id = Column(Integer, ForeignKey('nick_ids.nick_id'), primary_key=True)
|
||||
slug = Column(String(255), primary_key=True)
|
||||
canonical = Column(String(255))
|
||||
|
||||
|
||||
class NickValues(BASE):
|
||||
"""
|
||||
NickValues SQLAlchemy Class
|
||||
"""
|
||||
__tablename__ = 'spice_nick_values'
|
||||
nick_id = Column(Integer, ForeignKey('nick_ids.nick_id'), primary_key=True)
|
||||
namespace = Column(String(255), primary_key=True)
|
||||
key = Column(String(255), primary_key=True)
|
||||
value = Column(Text())
|
||||
|
||||
|
||||
class ChannelValues(BASE):
|
||||
"""
|
||||
ChannelValues SQLAlchemy Class
|
||||
"""
|
||||
__tablename__ = 'spice_channel_values'
|
||||
channel = Column(String(255), primary_key=True)
|
||||
namespace = Column(String(255), primary_key=True)
|
||||
key = Column(String(255), primary_key=True)
|
||||
value = Column(Text())
|
||||
|
||||
|
||||
class PluginValues(BASE):
|
||||
"""
|
||||
PluginValues SQLAlchemy Class
|
||||
"""
|
||||
__tablename__ = 'spice_plugin_values'
|
||||
plugin = Column(String(255), primary_key=True)
|
||||
namespace = Column(String(255), primary_key=True)
|
||||
key = Column(String(255), primary_key=True)
|
||||
value = Column(Text())
|
||||
|
||||
|
||||
class SpiceDB(object):
|
||||
|
||||
# NICK FUNCTIONS
|
||||
|
||||
def set_nick_value(self, nick, key, value, namespace='default'):
|
||||
"""Sets the value for a given key to be associated with the nick."""
|
||||
nick = Identifier(nick)
|
||||
value = json.dumps(value, ensure_ascii=False)
|
||||
nick_id = self.get_nick_id(nick)
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(NickValues) \
|
||||
.filter(NickValues.nick_id == nick_id) \
|
||||
.filter(NickValues.namespace == namespace)\
|
||||
.filter(NickValues.key == key) \
|
||||
.one_or_none()
|
||||
# NickValue exists, update
|
||||
if result:
|
||||
result.value = value
|
||||
session.commit()
|
||||
# DNE - Insert
|
||||
else:
|
||||
new_nickvalue = NickValues(nick_id=nick_id, namespace=namespace, key=key, value=value)
|
||||
session.add(new_nickvalue)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def get_nick_value(self, nick, key, namespace='default'):
|
||||
"""Retrieves the value for a given key associated with a nick."""
|
||||
nick = Identifier(nick)
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(NickValues) \
|
||||
.filter(Nicknames.nick_id == NickValues.nick_id) \
|
||||
.filter(Nicknames.slug == nick.lower()) \
|
||||
.filter(NickValues.namespace == namespace)\
|
||||
.filter(NickValues.key == key) \
|
||||
.one_or_none()
|
||||
if result is not None:
|
||||
result = result.value
|
||||
return _deserialize(result)
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def delete_nick_value(self, nick, key, namespace='default'):
|
||||
"""Deletes the value for a given key to be associated with the nick."""
|
||||
nick = Identifier(nick)
|
||||
nick_id = self.get_nick_id(nick)
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(NickValues) \
|
||||
.filter(NickValues.nick_id == nick_id) \
|
||||
.filter(NickValues.namespace == namespace)\
|
||||
.filter(NickValues.key == key) \
|
||||
.one_or_none()
|
||||
# NickValue exists, delete
|
||||
if result:
|
||||
session.delete(result)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def adjust_nick_value(self, nick, key, value, namespace='default'):
|
||||
"""Sets the value for a given key to be associated with the nick."""
|
||||
nick = Identifier(nick)
|
||||
value = json.dumps(value, ensure_ascii=False)
|
||||
nick_id = self.get_nick_id(nick)
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(NickValues) \
|
||||
.filter(NickValues.nick_id == nick_id) \
|
||||
.filter(NickValues.namespace == namespace)\
|
||||
.filter(NickValues.key == key) \
|
||||
.one_or_none()
|
||||
# NickValue exists, update
|
||||
if result:
|
||||
result.value = float(result.value) + float(value)
|
||||
session.commit()
|
||||
# DNE - Insert
|
||||
else:
|
||||
new_nickvalue = NickValues(nick_id=nick_id, namespace=namespace, key=key, value=float(value))
|
||||
session.add(new_nickvalue)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def adjust_nick_list(self, nick, key, entries, adjustmentdirection, namespace='default'):
|
||||
"""Sets the value for a given key to be associated with the nick."""
|
||||
nick = Identifier(nick)
|
||||
if not isinstance(entries, list):
|
||||
entries = [entries]
|
||||
entries = json.dumps(entries, ensure_ascii=False)
|
||||
nick_id = self.get_nick_id(nick)
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(NickValues) \
|
||||
.filter(NickValues.nick_id == nick_id) \
|
||||
.filter(NickValues.namespace == namespace)\
|
||||
.filter(NickValues.key == key) \
|
||||
.one_or_none()
|
||||
# NickValue exists, update
|
||||
if result:
|
||||
if adjustmentdirection == 'add':
|
||||
for entry in entries:
|
||||
if entry not in result.value:
|
||||
result.value.append(entry)
|
||||
elif adjustmentdirection == 'del':
|
||||
for entry in entries:
|
||||
while entry in result.value:
|
||||
result.value.remove(entry)
|
||||
session.commit()
|
||||
# DNE - Insert
|
||||
else:
|
||||
values = []
|
||||
if adjustmentdirection == 'add':
|
||||
for entry in entries:
|
||||
if entry not in values:
|
||||
values.append(entry)
|
||||
elif adjustmentdirection == 'del':
|
||||
for entry in entries:
|
||||
while entry in values:
|
||||
values.remove(entry)
|
||||
new_nickvalue = NickValues(nick_id=nick_id, namespace=namespace, key=key, value=values)
|
||||
session.add(new_nickvalue)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
# CHANNEL FUNCTIONS
|
||||
|
||||
def set_channel_value(self, channel, key, value, namespace='default'):
|
||||
"""Sets the value for a given key to be associated with the channel."""
|
||||
channel = Identifier(channel).lower()
|
||||
value = json.dumps(value, ensure_ascii=False)
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(ChannelValues) \
|
||||
.filter(ChannelValues.channel == channel)\
|
||||
.filter(ChannelValues.namespace == namespace)\
|
||||
.filter(ChannelValues.key == key) \
|
||||
.one_or_none()
|
||||
# ChannelValue exists, update
|
||||
if result:
|
||||
result.value = value
|
||||
session.commit()
|
||||
# DNE - Insert
|
||||
else:
|
||||
new_channelvalue = ChannelValues(channel=channel, namespace=namespace, key=key, value=value)
|
||||
session.add(new_channelvalue)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def get_channel_value(self, channel, key, namespace='default'):
|
||||
"""Retrieves the value for a given key associated with a channel."""
|
||||
channel = Identifier(channel).lower()
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(ChannelValues) \
|
||||
.filter(ChannelValues.channel == channel)\
|
||||
.filter(ChannelValues.namespace == namespace)\
|
||||
.filter(ChannelValues.key == key) \
|
||||
.one_or_none()
|
||||
if result is not None:
|
||||
result = result.value
|
||||
return _deserialize(result)
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def delete_channel_value(self, channel, key, namespace='default'):
|
||||
"""Sets the value for a given key to be associated with the channel."""
|
||||
channel = Identifier(channel).lower()
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(ChannelValues) \
|
||||
.filter(ChannelValues.channel == channel)\
|
||||
.filter(ChannelValues.namespace == namespace)\
|
||||
.filter(ChannelValues.key == key) \
|
||||
.one_or_none()
|
||||
# ChannelValue exists, delete
|
||||
if result:
|
||||
session.delete(result)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def adjust_channel_value(self, channel, key, value, namespace='default'):
|
||||
"""Sets the value for a given key to be associated with the channel."""
|
||||
channel = Identifier(channel).lower()
|
||||
value = json.dumps(value, ensure_ascii=False)
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(ChannelValues) \
|
||||
.filter(ChannelValues.channel == channel)\
|
||||
.filter(ChannelValues.namespace == namespace)\
|
||||
.filter(ChannelValues.key == key) \
|
||||
.one_or_none()
|
||||
# ChannelValue exists, update
|
||||
if result:
|
||||
result.value = float(result.value) + float(value)
|
||||
session.commit()
|
||||
# DNE - Insert
|
||||
else:
|
||||
new_channelvalue = ChannelValues(channel=channel, namespace=namespace, key=key, value=float(value))
|
||||
session.add(new_channelvalue)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def adjust_channel_list(self, channel, key, entries, adjustmentdirection, namespace='default'):
|
||||
"""Sets the value for a given key to be associated with the channel."""
|
||||
channel = Identifier(channel).lower()
|
||||
if not isinstance(entries, list):
|
||||
entries = [entries]
|
||||
entries = json.dumps(entries, ensure_ascii=False)
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(ChannelValues) \
|
||||
.filter(ChannelValues.channel == channel)\
|
||||
.filter(ChannelValues.namespace == namespace)\
|
||||
.filter(ChannelValues.key == key) \
|
||||
.one_or_none()
|
||||
# ChannelValue exists, update
|
||||
if result:
|
||||
if adjustmentdirection == 'add':
|
||||
for entry in entries:
|
||||
if entry not in result.value:
|
||||
result.value.append(entry)
|
||||
elif adjustmentdirection == 'del':
|
||||
for entry in entries:
|
||||
while entry in result.value:
|
||||
result.value.remove(entry)
|
||||
session.commit()
|
||||
# DNE - Insert
|
||||
else:
|
||||
values = []
|
||||
if adjustmentdirection == 'add':
|
||||
for entry in entries:
|
||||
if entry not in values:
|
||||
values.append(entry)
|
||||
elif adjustmentdirection == 'del':
|
||||
for entry in entries:
|
||||
while entry in values:
|
||||
values.remove(entry)
|
||||
new_channelvalue = ChannelValues(channel=channel, namespace=namespace, key=key, value=values)
|
||||
session.add(new_channelvalue)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
# PLUGIN FUNCTIONS
|
||||
|
||||
def set_plugin_value(self, plugin, key, value, namespace='default'):
|
||||
"""Sets the value for a given key to be associated with the plugin."""
|
||||
plugin = Identifier(plugin).lower()
|
||||
value = json.dumps(value, ensure_ascii=False)
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(PluginValues) \
|
||||
.filter(PluginValues.plugin == plugin)\
|
||||
.filter(PluginValues.namespace == namespace)\
|
||||
.filter(PluginValues.key == key) \
|
||||
.one_or_none()
|
||||
# PluginValues exists, update
|
||||
if result:
|
||||
result.value = value
|
||||
session.commit()
|
||||
# DNE - Insert
|
||||
else:
|
||||
new_pluginvalue = PluginValues(plugin=plugin, namespace=namespace, key=key, value=value)
|
||||
session.add(new_pluginvalue)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def get_plugin_value(self, plugin, key, namespace='default'):
|
||||
"""Retrieves the value for a given key associated with a plugin."""
|
||||
plugin = Identifier(plugin).lower()
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(PluginValues) \
|
||||
.filter(PluginValues.plugin == plugin)\
|
||||
.filter(PluginValues.namespace == namespace)\
|
||||
.filter(PluginValues.key == key) \
|
||||
.one_or_none()
|
||||
if result is not None:
|
||||
result = result.value
|
||||
return _deserialize(result)
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def delete_plugin_value(self, plugin, key, namespace='default'):
|
||||
"""Deletes the value for a given key to be associated with the plugin."""
|
||||
plugin = Identifier(plugin).lower()
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(PluginValues) \
|
||||
.filter(PluginValues.plugin == plugin)\
|
||||
.filter(PluginValues.namespace == namespace)\
|
||||
.filter(PluginValues.key == key) \
|
||||
.one_or_none()
|
||||
# PluginValues exists, delete
|
||||
if result:
|
||||
session.delete(result)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def adjust_plugin_value(self, plugin, key, value, namespace='default'):
|
||||
"""Sets the value for a given key to be associated with the plugin."""
|
||||
plugin = Identifier(plugin).lower()
|
||||
value = json.dumps(value, ensure_ascii=False)
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(PluginValues) \
|
||||
.filter(PluginValues.plugin == plugin)\
|
||||
.filter(PluginValues.namespace == namespace)\
|
||||
.filter(PluginValues.key == key) \
|
||||
.one_or_none()
|
||||
# ChannelValue exists, update
|
||||
if result:
|
||||
result.value = float(result.value) + float(value)
|
||||
session.commit()
|
||||
# DNE - Insert
|
||||
else:
|
||||
new_pluginvalue = PluginValues(plugin=plugin, namespace=namespace, key=key, value=float(value))
|
||||
session.add(new_pluginvalue)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def adjust_plugin_list(self, plugin, key, entries, adjustmentdirection, namespace='default'):
|
||||
"""Sets the value for a given key to be associated with the plugin."""
|
||||
plugin = Identifier(plugin).lower()
|
||||
if not isinstance(entries, list):
|
||||
entries = [entries]
|
||||
entries = json.dumps(entries, ensure_ascii=False)
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(PluginValues) \
|
||||
.filter(PluginValues.plugin == plugin)\
|
||||
.filter(PluginValues.namespace == namespace)\
|
||||
.filter(PluginValues.key == key) \
|
||||
.one_or_none()
|
||||
# ChannelValue exists, update
|
||||
if result:
|
||||
if adjustmentdirection == 'add':
|
||||
for entry in entries:
|
||||
if entry not in result.value:
|
||||
result.value.append(entry)
|
||||
elif adjustmentdirection == 'del':
|
||||
for entry in entries:
|
||||
while entry in result.value:
|
||||
result.value.remove(entry)
|
||||
session.commit()
|
||||
# DNE - Insert
|
||||
else:
|
||||
values = []
|
||||
if adjustmentdirection == 'add':
|
||||
for entry in entries:
|
||||
if entry not in values:
|
||||
values.append(entry)
|
||||
elif adjustmentdirection == 'del':
|
||||
for entry in entries:
|
||||
while entry in values:
|
||||
values.remove(entry)
|
||||
new_pluginvalue = PluginValues(plugin=plugin, namespace=namespace, key=key, value=values)
|
||||
session.add(new_pluginvalue)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
|
||||
class BotDatabase():
|
||||
"""A thread safe database cache"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
sopel.db.NickValues = NickValues
|
||||
SopelDB.get_nick_value = SpiceDB.get_nick_value
|
||||
SopelDB.set_nick_value = SpiceDB.set_nick_value
|
||||
SopelDB.delete_nick_value = SpiceDB.delete_nick_value
|
||||
SopelDB.adjust_nick_value = SpiceDB.adjust_nick_value
|
||||
SopelDB.adjust_nick_list = SpiceDB.adjust_nick_list
|
||||
|
||||
sopel.db.ChannelValues = ChannelValues
|
||||
SopelDB.get_channel_value = SpiceDB.get_channel_value
|
||||
SopelDB.set_channel_value = SpiceDB.set_channel_value
|
||||
SopelDB.delete_channel_value = SpiceDB.delete_channel_value
|
||||
SopelDB.adjust_channel_value = SpiceDB.adjust_channel_value
|
||||
SopelDB.adjust_channel_list = SpiceDB.adjust_channel_list
|
||||
|
||||
sopel.db.PluginValues = PluginValues
|
||||
SopelDB.get_plugin_value = SpiceDB.get_plugin_value
|
||||
SopelDB.set_plugin_value = SpiceDB.set_plugin_value
|
||||
SopelDB.delete_plugin_value = SpiceDB.delete_plugin_value
|
||||
SopelDB.adjust_plugin_value = SpiceDB.adjust_plugin_value
|
||||
SopelDB.adjust_plugin_list = SpiceDB.adjust_plugin_list
|
||||
|
||||
self.db = SopelDB(botconfig.config)
|
||||
BASE.metadata.create_all(self.db.engine)
|
||||
|
||||
"""Nick"""
|
||||
|
||||
def get_nick_id(self, nick, create=True):
|
||||
return self.db.get_nick_id(nick, create)
|
||||
|
||||
def get_nick_value(self, nick, key, namespace='default'):
|
||||
return self.db.get_nick_value(nick, key, namespace)
|
||||
|
||||
def set_nick_value(self, nick, key, value, namespace='default'):
|
||||
return self.db.set_nick_value(nick, key, value, namespace)
|
||||
|
||||
def delete_nick_value(self, nick, key, namespace='default'):
|
||||
return self.db.delete_nick_value(nick, key, namespace)
|
||||
|
||||
def adjust_nick_value(self, nick, key, value, namespace='default'):
|
||||
return self.db.adjust_nick_value(nick, key, value, namespace)
|
||||
|
||||
def adjust_nick_list(self, nick, key, entries, adjustmentdirection, namespace='default'):
|
||||
return self.db.adjust_nick_list(nick, key, entries, adjustmentdirection, namespace)
|
||||
|
||||
"""Bot"""
|
||||
|
||||
def get_bot_value(self, key, namespace='default'):
|
||||
return self.db.get_nick_value(botconfig.nick, key, namespace)
|
||||
|
||||
def set_bot_value(self, key, value, namespace='default'):
|
||||
return self.db.set_nick_value(botconfig.nick, key, value, namespace)
|
||||
|
||||
def delete_bot_value(self, key, namespace='default'):
|
||||
return self.db.delete_nick_value(botconfig.nick, key, namespace)
|
||||
|
||||
def adjust_bot_value(self, key, value, namespace='default'):
|
||||
return self.db.adjust_nick_value(botconfig.nick, key, value, namespace)
|
||||
|
||||
def adjust_bot_list(self, key, entries, adjustmentdirection, namespace='default'):
|
||||
return self.db.adjust_nick_list(botconfig.nick, key, entries, adjustmentdirection, namespace)
|
||||
|
||||
"""Channels"""
|
||||
|
||||
def get_channel_value(self, channel, key, namespace='default'):
|
||||
return self.db.get_channel_value(channel, key, namespace)
|
||||
|
||||
def set_channel_value(self, channel, key, value, namespace='default'):
|
||||
return self.db.set_channel_value(channel, key, value, namespace)
|
||||
|
||||
def delete_channel_value(self, channel, key, namespace='default'):
|
||||
return self.db.delete_channel_value(channel, key, namespace)
|
||||
|
||||
def adjust_channel_value(self, channel, key, value, namespace='default'):
|
||||
return self.db.adjust_channel_value(channel, key, value, namespace)
|
||||
|
||||
def adjust_channel_list(self, nick, key, entries, adjustmentdirection, namespace='default'):
|
||||
return self.db.adjust_channel_list(nick, key, entries, adjustmentdirection, namespace)
|
||||
|
||||
"""Plugins"""
|
||||
|
||||
def get_plugin_value(self, plugin, key, namespace='default'):
|
||||
return self.db.get_plugin_value(plugin, key, namespace)
|
||||
|
||||
def set_plugin_value(self, plugin, key, value, namespace='default'):
|
||||
return self.db.set_plugin_value(plugin, key, value, namespace)
|
||||
|
||||
def delete_plugin_value(self, plugin, key, namespace='default'):
|
||||
return self.db.delete_plugin_value(plugin, key, namespace)
|
||||
|
||||
def adjust_plugin_value(self, plugin, key, value, namespace='default'):
|
||||
return self.db.adjust_plugin_value(plugin, key, value, namespace)
|
||||
|
||||
def adjust_plugin_list(self, nick, key, entries, adjustmentdirection, namespace='default'):
|
||||
return self.db.adjust_plugin_list(nick, key, entries, adjustmentdirection, namespace)
|
||||
|
||||
|
||||
db = BotDatabase()
|
||||
@ -7,9 +7,16 @@ We utilize the Sopel code for event numbers and
|
||||
self-trigger the bot into performing actions
|
||||
"""
|
||||
|
||||
|
||||
import sopel
|
||||
import functools
|
||||
import threading
|
||||
import time
|
||||
|
||||
from .Logs import logs
|
||||
|
||||
|
||||
# TODO
|
||||
# full_message = ':{} PRIVMSG {} :{}'.format(hostmask, sender, msg)
|
||||
|
||||
|
||||
class BotEvents(object):
|
||||
@ -17,7 +24,7 @@ class BotEvents(object):
|
||||
|
||||
Events will be assigned a 4-digit number above 1000.
|
||||
|
||||
This allows you to do, ``@module.event(botevents.BOT_WELCOME)````
|
||||
This allows you to do, ``@module.event(events.BOT_WELCOME)````
|
||||
|
||||
Triggers handled by this module will be processed immediately.
|
||||
Others will be placed into a queue.
|
||||
@ -26,26 +33,30 @@ class BotEvents(object):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.lock = threading.Lock()
|
||||
self.RPL_WELCOME = '001' # This is a defined IRC event
|
||||
self.BOT_UPTIME = time.time()
|
||||
self.BOT_WELCOME = '1001'
|
||||
self.BOT_READY = '1002'
|
||||
self.BOT_CONNECTED = '1003'
|
||||
self.BOT_LOADED = '1004'
|
||||
self.BOT_RECONNECTED = '1005'
|
||||
self.defaultevents = [self.BOT_WELCOME, self.BOT_READY, self.BOT_CONNECTED, self.BOT_LOADED, self.BOT_RECONNECTED]
|
||||
self.SpiceBot_Events = {
|
||||
"assigned_IDs": {1000: "Default", 1001: "BOT_WELCOME", 1002: "BOT_READY", 1003: "BOT_CONNECTED", 1004: "BOT_LOADED", 1005: "BOT_RECONNECTED"},
|
||||
"triggers_recieved": {},
|
||||
"trigger_queue": [],
|
||||
"startup_required": [self.BOT_WELCOME, self.BOT_READY, self.BOT_CONNECTED],
|
||||
"RPL_WELCOME_Count": 0
|
||||
}
|
||||
self.dict = {
|
||||
"assigned_IDs": {1000: "BOT_UPTIME", 1001: "BOT_WELCOME", 1002: "BOT_READY", 1003: "BOT_CONNECTED", 1004: "BOT_LOADED", 1005: "BOT_RECONNECTED"},
|
||||
"triggers_recieved": {},
|
||||
"trigger_queue": [],
|
||||
"startup_required": [self.BOT_WELCOME, self.BOT_READY, self.BOT_CONNECTED],
|
||||
"RPL_WELCOME_Count": 0
|
||||
}
|
||||
|
||||
def __getattr__(self, name):
|
||||
''' will only get called for undefined attributes '''
|
||||
eventnumber = max(list(self.SpiceBot_Events["assigned_IDs"].keys())) + 1
|
||||
self.SpiceBot_Events["assigned_IDs"][eventnumber] = str(name)
|
||||
self.lock.acquire()
|
||||
eventnumber = max(list(self.dict["assigned_IDs"].keys())) + 1
|
||||
self.dict["assigned_IDs"][eventnumber] = str(name)
|
||||
setattr(self, name, str(eventnumber))
|
||||
self.lock.release()
|
||||
return str(eventnumber)
|
||||
|
||||
def trigger(self, bot, number, message="SpiceBot_Events"):
|
||||
@ -53,7 +64,7 @@ class BotEvents(object):
|
||||
if number in self.defaultevents:
|
||||
self.dispatch(bot, pretriggerdict)
|
||||
else:
|
||||
self.SpiceBot_Events["trigger_queue"].append(pretriggerdict)
|
||||
self.dict["trigger_queue"].append(pretriggerdict)
|
||||
|
||||
def dispatch(self, bot, pretriggerdict):
|
||||
number = pretriggerdict["number"]
|
||||
@ -66,43 +77,51 @@ class BotEvents(object):
|
||||
self.recieved({"number": number, "message": message})
|
||||
|
||||
def recieved(self, trigger):
|
||||
self.lock.acquire()
|
||||
|
||||
if isinstance(trigger, dict):
|
||||
eventnumber = str(trigger["number"])
|
||||
message = str(trigger["message"])
|
||||
else:
|
||||
eventnumber = str(trigger.event)
|
||||
message = trigger.args[1]
|
||||
if eventnumber not in self.SpiceBot_Events["triggers_recieved"]:
|
||||
self.SpiceBot_Events["triggers_recieved"][eventnumber] = []
|
||||
self.SpiceBot_Events["triggers_recieved"][eventnumber].append(message)
|
||||
logs.log('SpiceBot_Events', str(eventnumber) + " " + str(message))
|
||||
if eventnumber not in self.dict["triggers_recieved"]:
|
||||
self.dict["triggers_recieved"][eventnumber] = []
|
||||
self.dict["triggers_recieved"][eventnumber].append(message)
|
||||
self.lock.release()
|
||||
|
||||
def check(self, checklist):
|
||||
if not isinstance(checklist, list):
|
||||
checklist = [str(checklist)]
|
||||
for number in checklist:
|
||||
if str(number) not in self.SpiceBot_Events["triggers_recieved"].keys():
|
||||
if str(number) not in self.dict["triggers_recieved"].keys():
|
||||
return False
|
||||
return True
|
||||
|
||||
def startup_add(self, startlist):
|
||||
self.lock.acquire()
|
||||
if not isinstance(startlist, list):
|
||||
startlist = [str(startlist)]
|
||||
self.SpiceBot_Events["startup_required"].extend(startlist)
|
||||
for eventitem in startlist:
|
||||
if eventitem not in self.dict["startup_required"]:
|
||||
self.dict["startup_required"].append(eventitem)
|
||||
self.lock.release()
|
||||
|
||||
def startup_check(self):
|
||||
for number in self.SpiceBot_Events["startup_required"]:
|
||||
if str(number) not in self.SpiceBot_Events["triggers_recieved"].keys():
|
||||
for number in self.dict["startup_required"]:
|
||||
if str(number) not in self.dict["triggers_recieved"].keys():
|
||||
return False
|
||||
return True
|
||||
|
||||
def startup_debug(self):
|
||||
not_done = []
|
||||
for number in self.SpiceBot_Events["startup_required"]:
|
||||
if str(number) not in self.SpiceBot_Events["triggers_recieved"].keys():
|
||||
for number in self.dict["startup_required"]:
|
||||
if str(number) not in self.dict["triggers_recieved"].keys():
|
||||
not_done.append(int(number))
|
||||
reference_not_done = []
|
||||
for item in not_done:
|
||||
reference_not_done.append(str(self.SpiceBot_Events["assigned_IDs"][item]))
|
||||
reference_not_done.append(str(self.dict["assigned_IDs"][item]))
|
||||
return reference_not_done
|
||||
|
||||
def check_ready(self, checklist):
|
||||
@ -126,4 +145,4 @@ class BotEvents(object):
|
||||
return actual_decorator
|
||||
|
||||
|
||||
botevents = BotEvents()
|
||||
events = BotEvents()
|
||||
|
||||
37
sopel_modules/SpiceBot/Kick.py
Normal file
37
sopel_modules/SpiceBot/Kick.py
Normal file
@ -0,0 +1,37 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot Update system.
|
||||
"""
|
||||
|
||||
from sopel.config.types import StaticSection, ValidatedAttribute
|
||||
|
||||
|
||||
class SpiceBot_Kick(StaticSection):
|
||||
kick = ValidatedAttribute('kick', default=1)
|
||||
|
||||
|
||||
class SopelKICK:
|
||||
|
||||
def kick(self, nick, channel, text=None):
|
||||
"""Send an IRC KICK command.
|
||||
Within the context of a triggered callable, ``channel`` will default to the
|
||||
channel in which the call was triggered. If triggered from a private message,
|
||||
``channel`` is required (or the call to ``kick()`` will be ignored).
|
||||
The bot must be a channel operator in specified channel for this to work.
|
||||
.. versionadded:: 7.0
|
||||
"""
|
||||
self.write(['KICK', channel, nick], text)
|
||||
|
||||
|
||||
class SopelWrapperKICK(object):
|
||||
|
||||
def kick(self, nick, channel=None, message=None):
|
||||
if channel is None:
|
||||
if self._trigger.is_privmsg:
|
||||
raise RuntimeError('Error: KICK requires a channel.')
|
||||
else:
|
||||
channel = self._trigger.sender
|
||||
if nick is None:
|
||||
raise RuntimeError('Error: KICK requires a nick.')
|
||||
self._bot.kick(nick, channel, message)
|
||||
@ -6,51 +6,74 @@ This is the SpiceBot Logs system.
|
||||
This Class stores logs in an easy to access manner
|
||||
"""
|
||||
|
||||
|
||||
import sopel
|
||||
import threading
|
||||
import os
|
||||
import sys
|
||||
import spicemanip
|
||||
|
||||
from .Config import config as botconfig
|
||||
|
||||
class botlogs():
|
||||
|
||||
# TODO timestamps
|
||||
|
||||
class BotLogs():
|
||||
"""This Is a contained source of log information"""
|
||||
def __init__(self):
|
||||
self.SpiceBot_Logs = {
|
||||
"list": {"Sopel_systemd": [], "Sopel_stdio": []},
|
||||
"queue": []
|
||||
}
|
||||
self.sopel_config = {
|
||||
"logging_channel": True
|
||||
}
|
||||
self.setup_logs()
|
||||
self.lock = threading.Lock()
|
||||
self.dict = {
|
||||
"list": {"Sopel_systemd": [], "Sopel_stdio": []},
|
||||
"queue": []
|
||||
}
|
||||
|
||||
def setup_logs(self):
|
||||
botconfig.core.logs_stdio = os.path.join(botconfig.core.logdir, 'stdio.log')
|
||||
# botconfig.core.logs_stdio = os.path.os.path.join(botconfig.core.logdir, botconfig.basename + '.stdio.log')
|
||||
botconfig.core.logs_exceptions = os.path.join(botconfig.core.logdir, 'exceptions.log')
|
||||
# botconfig.core.logs_exceptions = os.path.os.path.join(botconfig.core.logdir, botconfig.basename + '.exceptions.log')
|
||||
botconfig.core.logs_raw = os.path.join(botconfig.core.logdir, 'raw.log')
|
||||
# botconfig.core.logs_raw = os.path.os.path.join(botconfig.core.logdir, botconfig.basename + '.raw.log')
|
||||
|
||||
def botstderr(self, logmessage):
|
||||
sys.stderr.write(logmessage)
|
||||
|
||||
def log(self, logtype, logentry, stdio=False):
|
||||
|
||||
self.lock.acquire()
|
||||
|
||||
logtitle = "[" + logtype + "]"
|
||||
logmessage = logtitle + " " + logentry
|
||||
|
||||
if self.sopel_config["logging_channel"]:
|
||||
self.SpiceBot_Logs["queue"].append(logmessage)
|
||||
if botconfig.logging_channel:
|
||||
self.dict["queue"].append(logmessage)
|
||||
|
||||
if stdio:
|
||||
sopel.tools.stderr(logmessage)
|
||||
self.botstderr(logmessage)
|
||||
|
||||
if logtype not in self.SpiceBot_Logs["list"].keys():
|
||||
self.SpiceBot_Logs["list"][logtype] = []
|
||||
self.SpiceBot_Logs["list"][logtype].append(logentry)
|
||||
if logtype not in self.dict["list"].keys():
|
||||
self.dict["list"][logtype] = []
|
||||
self.dict["list"][logtype].append(logentry)
|
||||
|
||||
def get_logs(self):
|
||||
return []
|
||||
self.lock.release()
|
||||
|
||||
def stdio_logs_fetch(self, bot):
|
||||
def get_logs(self, logtype):
|
||||
if logtype == "Sopel_systemd":
|
||||
logindex = self.systemd_logs_fetch()
|
||||
elif logtype == "Sopel_stdio":
|
||||
logindex = self.stdio_logs_fetch()
|
||||
else:
|
||||
logindex = self.dict["list"][logtype]
|
||||
return logindex
|
||||
|
||||
def stdio_logs_fetch(self):
|
||||
|
||||
stdio_ignore = []
|
||||
for logtype in botlogs.SpiceBot_Logs["list"].keys():
|
||||
for logtype in self.dict["list"].keys():
|
||||
stdio_ignore.append("[" + logtype + "]")
|
||||
|
||||
logfile = os.path.os.path.join(bot.config.core.logdir, 'stdio.log')
|
||||
|
||||
try:
|
||||
log_file_lines = []
|
||||
log_file = open(logfile, 'r')
|
||||
log_file = open(botconfig.logs_stdio, 'r')
|
||||
lines = log_file.readlines()
|
||||
for line in lines:
|
||||
log_file_lines.append(line)
|
||||
@ -80,8 +103,8 @@ class botlogs():
|
||||
|
||||
return debuglines
|
||||
|
||||
def systemd_logs_fetch(self, bot):
|
||||
servicepid = self.get_running_pid(bot)
|
||||
def systemd_logs_fetch(self):
|
||||
servicepid = self.get_running_pid()
|
||||
debuglines = []
|
||||
for line in os.popen(str("sudo journalctl _PID=" + str(servicepid))).read().split('\n'):
|
||||
line = str(line).split(str(os.uname()[1] + " "))[-1]
|
||||
@ -92,15 +115,15 @@ class botlogs():
|
||||
debuglines.append(str(line))
|
||||
return debuglines
|
||||
|
||||
def get_running_pid(self, bot):
|
||||
def get_running_pid(self):
|
||||
try:
|
||||
filename = "/run/sopel/sopel-" + str(bot.nick) + ".pid"
|
||||
filename = "/run/sopel/sopel-" + str(botconfig.nick) + ".pid"
|
||||
with open(filename, 'r') as pid_file:
|
||||
pidnum = int(pid_file.read())
|
||||
except Exception as e:
|
||||
pidnum = e
|
||||
pidnum = str(os.popen("systemctl show " + str(bot.nick) + " --property=MainPID").read()).split("=")[-1]
|
||||
pidnum = str(os.popen("systemctl show " + str(botconfig.nick) + " --property=MainPID").read()).split("=")[-1]
|
||||
return pidnum
|
||||
|
||||
|
||||
botlogs = botlogs()
|
||||
logs = BotLogs()
|
||||
|
||||
198
sopel_modules/SpiceBot/Prerun.py
Normal file
198
sopel_modules/SpiceBot/Prerun.py
Normal file
@ -0,0 +1,198 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot Prerun system.
|
||||
"""
|
||||
|
||||
from sopel.tools import Identifier
|
||||
|
||||
import functools
|
||||
import copy
|
||||
import datetime
|
||||
import spicemanip
|
||||
|
||||
from .Tools import command_permissions_check
|
||||
from .Commands import commands as botcommands
|
||||
from .Database import db as botdb
|
||||
|
||||
|
||||
class BotPrerun():
|
||||
def __init__(self):
|
||||
self.dict = {}
|
||||
|
||||
"""Command Splitting"""
|
||||
|
||||
def prerun(self, trigger_command_type='module'):
|
||||
def actual_decorator(function):
|
||||
|
||||
@functools.wraps(function)
|
||||
def internal_prerun(bot, trigger, *args, **kwargs):
|
||||
|
||||
# Primary command used for trigger, and a list of all words
|
||||
trigger_args, trigger_command = self.trigger_args(trigger.args[1], trigger_command_type)
|
||||
|
||||
# Argsdict Defaults
|
||||
argsdict_default = {}
|
||||
argsdict_default["type"] = trigger_command_type
|
||||
argsdict_default["com"] = trigger_command
|
||||
|
||||
realcom = botcommands.get_realcom(argsdict_default["com"], trigger_command_type)
|
||||
argsdict_default["realcom"] = realcom
|
||||
|
||||
# split into && groupings
|
||||
and_split = self.trigger_and_split(trigger_args)
|
||||
|
||||
# Create dict listings for trigger.sb
|
||||
argsdict_list = self.trigger_argsdict_list(argsdict_default, and_split)
|
||||
|
||||
# Run the function for all splits
|
||||
for argsdict in argsdict_list:
|
||||
trigger.sb = copy.deepcopy(argsdict)
|
||||
|
||||
trigger.sb["args"], trigger.sb["hyphen_arg"] = self.trigger_hyphen_args(trigger.sb["args"])
|
||||
if not trigger.sb["hyphen_arg"]:
|
||||
# check if anything prohibits the nick from running the command
|
||||
if self.trigger_runstatus(bot, trigger):
|
||||
function(bot, trigger, *args, **kwargs)
|
||||
else:
|
||||
self.trigger_hyphen_arg_handler(bot, trigger)
|
||||
return
|
||||
|
||||
return internal_prerun
|
||||
return actual_decorator
|
||||
|
||||
def trigger_args(self, triggerargs_one, trigger_command_type='module'):
|
||||
trigger_args = spicemanip.main(triggerargs_one, 'create')
|
||||
if trigger_command_type in ['nickname']:
|
||||
trigger_command = spicemanip.main(trigger_args, 2).lower()
|
||||
trigger_args = spicemanip.main(trigger_args, '3+', 'list')
|
||||
else:
|
||||
trigger_command = spicemanip.main(trigger_args, 1).lower()[1:]
|
||||
trigger_args = spicemanip.main(trigger_args, '2+', 'list')
|
||||
return trigger_args, trigger_command
|
||||
|
||||
def trigger_and_split(self, trigger_args):
|
||||
trigger_args_list_split = spicemanip.main(trigger_args, "split_&&")
|
||||
if not len(trigger_args_list_split):
|
||||
trigger_args_list_split.append([])
|
||||
return trigger_args_list_split
|
||||
|
||||
def trigger_argsdict_list(self, argsdict_default, and_split):
|
||||
prerun_split = []
|
||||
for trigger_args_part in and_split:
|
||||
argsdict_part = copy.deepcopy(argsdict_default)
|
||||
argsdict_part["args"] = spicemanip.main(trigger_args_part, 'create')
|
||||
if len(argsdict_part["args"]) and argsdict_part["args"][0] == "-a":
|
||||
argsdict_part["adminswitch"] = True
|
||||
argsdict_part["args"] = spicemanip.main(argsdict_part["args"], '2+', 'list')
|
||||
else:
|
||||
argsdict_part["adminswitch"] = False
|
||||
prerun_split.append(argsdict_part)
|
||||
return prerun_split
|
||||
|
||||
def trigger_runstatus(self, bot, trigger):
|
||||
return True
|
||||
|
||||
# Bots can't run commands
|
||||
if Identifier(trigger.nick) == bot.nick:
|
||||
return False
|
||||
|
||||
# Allow permissions for enabling and disabling commands via hyphenargs
|
||||
if trigger.sb["adminswitch"]:
|
||||
if command_permissions_check(bot, trigger, ['admins', 'owner', 'OP', 'ADMIN', 'OWNER']):
|
||||
return True
|
||||
else:
|
||||
bot.osd("The admin switch (-a) is for use by authorized nicks ONLY.", 'notice')
|
||||
return False
|
||||
|
||||
# don't run commands that are disabled in channels
|
||||
if not trigger.is_privmsg:
|
||||
commandused = trigger.sb["realcom"]
|
||||
disabled_list = botdb.get_channel_value(trigger.sender, 'commands_disabled') or {}
|
||||
if commandused in disabled_list.keys():
|
||||
reason = disabled_list[trigger.sb["realcom"]]["reason"]
|
||||
timestamp = disabled_list[trigger.sb["realcom"]]["timestamp"]
|
||||
bywhom = disabled_list[trigger.sb["realcom"]]["disabledby"]
|
||||
message = "The " + str(trigger.sb["com"]) + " command was disabled by " + bywhom + " in " + str(trigger.sender) + " at " + str(timestamp) + " for the following reason: " + str(reason)
|
||||
return self.trigger_cant_run(bot, trigger, message)
|
||||
|
||||
return True
|
||||
|
||||
def trigger_cant_run(self, bot, trigger, message=None):
|
||||
if message:
|
||||
bot.osd(message, trigger.nick, 'notice')
|
||||
if command_permissions_check(bot, trigger, ['admins', 'owner', 'OP', 'ADMIN', 'OWNER']):
|
||||
bot.osd("You however are authorized to bypass this warning with the (-a) admin switch.", trigger.nick, 'notice')
|
||||
return False
|
||||
|
||||
def trigger_hyphen_args(self, trigger_args_part):
|
||||
valid_hyphen_args = [
|
||||
'check',
|
||||
'enable', 'disable'
|
||||
]
|
||||
hyphen_args = []
|
||||
trigger_args_unhyphend = []
|
||||
for worditem in trigger_args_part:
|
||||
if str(worditem).startswith("--") and worditem[2:] in valid_hyphen_args:
|
||||
hyphen_args.append(worditem[2:])
|
||||
else:
|
||||
trigger_args_unhyphend.append(worditem)
|
||||
if len(hyphen_args):
|
||||
hyphenarg = hyphen_args[0]
|
||||
else:
|
||||
hyphenarg = None
|
||||
return trigger_args_unhyphend, hyphenarg
|
||||
|
||||
def trigger_hyphen_arg_handler(self, bot, trigger):
|
||||
|
||||
# Commands that cannot run via privmsg
|
||||
if trigger.sb["hyphen_arg"] in ['check']:
|
||||
if trigger.sb["com"].lower() != trigger.sb["realcom"]:
|
||||
bot.osd(trigger.sb["com"] + " is a valid alias command for " + trigger.sb["realcom"])
|
||||
else:
|
||||
bot.osd(trigger.sb["com"] + " is a valid command")
|
||||
return
|
||||
|
||||
elif trigger.sb["hyphen_arg"] in ['enable']:
|
||||
|
||||
if not command_permissions_check(bot, trigger, ['admins', 'owner', 'OP', 'ADMIN', 'OWNER']):
|
||||
bot.osd("I was unable to disable this command due to privilege issues.")
|
||||
return
|
||||
|
||||
if trigger.is_privmsg:
|
||||
bot.osd("This command must be run in a channel you which to enable it in.", trigger.nick, 'notice')
|
||||
return
|
||||
|
||||
if not botcommands.check_commands_disabled(trigger.sb["realcom"], trigger.sender):
|
||||
bot.osd(trigger.sb["com"] + " is already enabled in " + str(trigger.sender), trigger.nick, 'notice')
|
||||
return
|
||||
|
||||
botcommands.unset_command_disabled(trigger.sb["realcom"], trigger.sender)
|
||||
bot.osd(trigger.sb["com"] + " is now enabled in " + str(trigger.sender))
|
||||
return
|
||||
|
||||
elif trigger.sb["hyphen_arg"] in ['disable']:
|
||||
|
||||
if not command_permissions_check(bot, trigger, ['admins', 'owner', 'OP', 'ADMIN', 'OWNER']):
|
||||
bot.osd("I was unable to disable this command due to privilege issues.")
|
||||
return
|
||||
|
||||
if trigger.is_privmsg:
|
||||
bot.osd("This command must be run in a channel you which to disable it in.", trigger.nick, 'notice')
|
||||
return
|
||||
|
||||
if botcommands.check_commands_disabled(trigger.sb["realcom"], trigger.sender):
|
||||
bot.osd(trigger.sb["com"] + " is already disabled in " + str(trigger.sender), trigger.nick, 'notice')
|
||||
return
|
||||
|
||||
trailingmessage = spicemanip.main(trigger.sb["args"], 0) or "No reason given."
|
||||
timestamp = str(datetime.datetime.utcnow())
|
||||
|
||||
botcommands.set_command_disabled(trigger.sb["realcom"], trigger.sender, timestamp, trailingmessage, trigger.nick)
|
||||
bot.osd(trigger.sb["com"] + " is now disabled in " + str(trigger.sender))
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
|
||||
prerun = BotPrerun()
|
||||
13
sopel_modules/SpiceBot/StartupMonologue.py
Normal file
13
sopel_modules/SpiceBot/StartupMonologue.py
Normal file
@ -0,0 +1,13 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""StartupMonologue class"""
|
||||
|
||||
|
||||
class BotMonologue():
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.dict = {}
|
||||
|
||||
|
||||
startupmonologue = BotMonologue()
|
||||
@ -7,7 +7,6 @@ from __future__ import unicode_literals, absolute_import, print_function, divisi
|
||||
import sopel
|
||||
|
||||
import collections
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import codecs
|
||||
@ -20,7 +19,8 @@ from pygit2 import clone_repository
|
||||
|
||||
import spicemanip
|
||||
|
||||
from sopel_modules.SpiceBot.Logs import botlogs
|
||||
from .Logs import logs
|
||||
from .Config import config as botconfig
|
||||
|
||||
|
||||
"""Variable References"""
|
||||
@ -39,27 +39,10 @@ github_dict = {
|
||||
"""Sopel Wrapping Tools"""
|
||||
|
||||
|
||||
def sopel_triggerargs(bot, trigger, command_type='module_command'):
|
||||
triggerargs = []
|
||||
|
||||
if len(trigger.args) > 1:
|
||||
triggerargs = spicemanip.main(trigger.args[1], 'create')
|
||||
triggerargs = spicemanip.main(triggerargs, 'create')
|
||||
|
||||
if command_type in ['nickname_command']:
|
||||
command = spicemanip.main(triggerargs, 2).lower()
|
||||
triggerargs = spicemanip.main(triggerargs, '3+', 'list')
|
||||
else:
|
||||
command = spicemanip.main(triggerargs, 1).lower()[1:]
|
||||
triggerargs = spicemanip.main(triggerargs, '2+', 'list')
|
||||
|
||||
return triggerargs, command
|
||||
|
||||
|
||||
def bot_privs(bot, privtype):
|
||||
def bot_privs(privtype):
|
||||
if privtype == 'owners':
|
||||
privtype = 'owner'
|
||||
botpriveval = eval("bot.config.core." + privtype)
|
||||
botpriveval = eval("botconfig." + privtype)
|
||||
if not isinstance(botpriveval, list):
|
||||
botpriveval = [botpriveval]
|
||||
return botpriveval
|
||||
@ -71,8 +54,8 @@ def command_permissions_check(bot, trigger, privslist):
|
||||
|
||||
for botpriv in ["admins", "owner"]:
|
||||
if botpriv in privslist:
|
||||
botpriveval = bot_privs(bot, botpriv)
|
||||
if not inlist(bot, trigger.nick, botpriveval):
|
||||
botpriveval = bot_privs(botpriv)
|
||||
if not inlist(trigger.nick, botpriveval):
|
||||
commandrunconsensus.append('False')
|
||||
else:
|
||||
commandrunconsensus.append('True')
|
||||
@ -81,7 +64,7 @@ def command_permissions_check(bot, trigger, privslist):
|
||||
for chanpriv in ['OP', 'HOP', 'VOICE', 'OWNER', 'ADMIN']:
|
||||
if chanpriv in privslist:
|
||||
chanpriveval = channel_privs(bot, trigger.sender, chanpriv)
|
||||
if not inlist(bot, trigger.nick, chanpriveval):
|
||||
if not inlist(trigger.nick, chanpriveval):
|
||||
commandrunconsensus.append('False')
|
||||
else:
|
||||
commandrunconsensus.append('True')
|
||||
@ -135,7 +118,7 @@ def humanized_time(countdownseconds):
|
||||
"""Online Information Requests"""
|
||||
|
||||
|
||||
def googlesearch(bot, searchterm, searchtype=None):
|
||||
def googlesearch(searchterm, searchtype=None):
|
||||
header = {'User-Agent': str(UserAgent().chrome)}
|
||||
data = searchterm.replace(' ', '+')
|
||||
lookfor = data.replace(':', '%3A')
|
||||
@ -157,7 +140,7 @@ def googlesearch(bot, searchterm, searchtype=None):
|
||||
"""List Manipulation Functions"""
|
||||
|
||||
|
||||
def inlist(bot, searchterm, searchlist):
|
||||
def inlist(searchterm, searchlist):
|
||||
|
||||
# verify we are searching a list
|
||||
if isinstance(searchlist, collections.abc.KeysView) or isinstance(searchlist, dict):
|
||||
@ -178,7 +161,7 @@ def inlist(bot, searchterm, searchlist):
|
||||
return False
|
||||
|
||||
|
||||
def inlist_match(bot, searchterm, searchlist):
|
||||
def inlist_match(searchterm, searchlist):
|
||||
# verify we are searching a list
|
||||
if isinstance(searchlist, collections.abc.KeysView) or isinstance(searchlist, dict):
|
||||
searchlist = [x for x in searchlist]
|
||||
@ -202,7 +185,7 @@ def similar(a, b):
|
||||
return SequenceMatcher(None, a, b).ratio()
|
||||
|
||||
|
||||
def similar_list(bot, searchitem, searchlist, matchcount=1, searchorder='reverse'):
|
||||
def similar_list(searchitem, searchlist, matchcount=1, searchorder='reverse'):
|
||||
|
||||
if sys.version_info.major >= 3:
|
||||
if isinstance(searchlist, abc.KeysView):
|
||||
@ -231,7 +214,7 @@ def similar_list(bot, searchitem, searchlist, matchcount=1, searchorder='reverse
|
||||
return sim_listitems
|
||||
|
||||
|
||||
def array_arrangesort(bot, sortbyarray, arrayb):
|
||||
def array_arrangesort(sortbyarray, arrayb):
|
||||
sortbyarray, arrayb = (list(x) for x in zip(*sorted(zip(sortbyarray, arrayb), key=itemgetter(0))))
|
||||
return sortbyarray, arrayb
|
||||
|
||||
@ -246,12 +229,6 @@ def letters_in_string(text):
|
||||
"""Channel Functions"""
|
||||
|
||||
|
||||
def topic_compile(topic):
|
||||
actual_topic = re.compile(r'^\[\+[a-zA-Z]+\] (.*)')
|
||||
topic = re.sub(actual_topic, r'\1', topic)
|
||||
return topic
|
||||
|
||||
|
||||
def channel_privs(bot, channel, privtype):
|
||||
privlist = []
|
||||
for user in bot.channels[channel].privileges.keys():
|
||||
@ -273,7 +250,7 @@ def channel_privs(bot, channel, privtype):
|
||||
"""Environment Functions"""
|
||||
|
||||
|
||||
def stock_modules_begone(bot):
|
||||
def stock_modules_begone():
|
||||
|
||||
# Remove stock modules, if present
|
||||
main_sopel_dir = os.path.dirname(os.path.abspath(sopel.__file__))
|
||||
@ -297,7 +274,7 @@ def stock_modules_begone(bot):
|
||||
os.system("sudo mv " + path + " " + stockdir)
|
||||
|
||||
|
||||
def spicebot_update(bot, deps=False):
|
||||
def spicebot_update(deps=False):
|
||||
|
||||
if not os.path.exists("/tmp") or not os.path.isdir("/tmp"):
|
||||
os.system("sudo mkdir /tmp")
|
||||
@ -305,48 +282,48 @@ def spicebot_update(bot, deps=False):
|
||||
if not os.path.exists(clonepath) or not os.path.isdir(clonepath):
|
||||
os.system(clonepath)
|
||||
|
||||
botlogs.log('SpiceBot_Update', "Cloning to " + clonepath, True)
|
||||
logs.log('SpiceBot_Update', "Cloning to " + clonepath, True)
|
||||
|
||||
clone_repository(str(bot.config.SpiceBot_Update.gitrepo + ".git"), clonepath, checkout_branch=bot.config.SpiceBot_Update.gitbranch)
|
||||
clone_repository(str(botconfig.SpiceBot_Update.gitrepo + ".git"), clonepath, checkout_branch=botconfig.SpiceBot_Update.gitbranch)
|
||||
|
||||
pipcommand = "sudo pip3 install --upgrade"
|
||||
if not deps:
|
||||
pipcommand += " --no-deps"
|
||||
pipcommand += " --force-reinstall"
|
||||
# pipcommand += " git+" + str(bot.config.SpiceBot_Update.gitrepo) + "@" + str(bot.config.SpiceBot_Update.gitbranch)
|
||||
# pipcommand += " git+" + str(botconfig.SpiceBot_Update.gitrepo) + "@" + str(botconfig.SpiceBot_Update.gitbranch)
|
||||
pipcommand += " /tmp/SpiceBot/"
|
||||
|
||||
botlogs.log('SpiceBot_Update', "Running `" + pipcommand + "`", True)
|
||||
logs.log('SpiceBot_Update', "Running `" + pipcommand + "`", True)
|
||||
# for line in os.popen(pipcommand).read().split('\n'):
|
||||
# botlogs.log('SpiceBot_Update', " " + line)
|
||||
# logs.log('SpiceBot_Update', " " + line)
|
||||
os.system(pipcommand)
|
||||
|
||||
botlogs.log('SpiceBot_Update', "Deleting " + clonepath, True)
|
||||
logs.log('SpiceBot_Update', "Deleting " + clonepath, True)
|
||||
|
||||
os.system("sudo rm -r /tmp/SpiceBot")
|
||||
|
||||
stock_modules_begone(bot)
|
||||
stock_modules_begone()
|
||||
|
||||
|
||||
def spicebot_reload(bot, log_from='service_manip', quitmessage='Recieved QUIT'):
|
||||
# service_manip(bot, bot.nick, 'restart', log_from)
|
||||
# service_manip(bot.nick, 'restart', log_from)
|
||||
bot.restart(quitmessage)
|
||||
|
||||
|
||||
def service_manip(bot, servicename, dowhat, log_from='service_manip'):
|
||||
def service_manip(servicename, dowhat, log_from='service_manip'):
|
||||
if str(dowhat) not in ["start", "stop", "restart"]:
|
||||
return
|
||||
try:
|
||||
botlogs.log(log_from, str(dowhat).title() + "ing " + str(servicename) + ".service.")
|
||||
logs.log(log_from, str(dowhat).title() + "ing " + str(servicename) + ".service.")
|
||||
os.system("sudo service " + str(servicename) + " " + str(dowhat))
|
||||
except Exception as e:
|
||||
botlogs.log(log_from, str(dowhat).title() + "ing " + str(servicename) + ".service Failed: " + str(e))
|
||||
logs.log(log_from, str(dowhat).title() + "ing " + str(servicename) + ".service Failed: " + str(e))
|
||||
|
||||
|
||||
"""Config Reading Functions"""
|
||||
|
||||
|
||||
def read_directory_json_to_dict(bot, directories, configtypename="Config File", log_from='read_directory_json_to_dict'):
|
||||
def read_directory_json_to_dict(directories, configtypename="Config File", log_from='read_directory_json_to_dict', logging=True):
|
||||
|
||||
if not isinstance(directories, list):
|
||||
directories = [directories]
|
||||
@ -371,8 +348,8 @@ def read_directory_json_to_dict(bot, directories, configtypename="Config File",
|
||||
dict_from_file = eval(infread)
|
||||
except Exception as e:
|
||||
filereadgood = False
|
||||
if bot:
|
||||
botlogs.log(log_from, "Error loading %s: %s (%s)" % (configtypename, e, filepath))
|
||||
if logging:
|
||||
logs.log(log_from, "Error loading %s: %s (%s)" % (configtypename, e, filepath))
|
||||
dict_from_file = dict()
|
||||
# Close File
|
||||
inf.close()
|
||||
@ -386,11 +363,11 @@ def read_directory_json_to_dict(bot, directories, configtypename="Config File",
|
||||
fileopenfail += 1
|
||||
|
||||
if filecount:
|
||||
if bot:
|
||||
botlogs.log(log_from, 'Registered %d %s dict files,' % (filecount, configtypename))
|
||||
botlogs.log(log_from, '%d %s dict files failed to load' % (fileopenfail, configtypename), True)
|
||||
if logging:
|
||||
logs.log(log_from, 'Registered %d %s dict files,' % (filecount, configtypename))
|
||||
logs.log(log_from, '%d %s dict files failed to load' % (fileopenfail, configtypename), True)
|
||||
else:
|
||||
if bot:
|
||||
botlogs.log(log_from, "Warning: Couldn't load any %s dict files" % (configtypename))
|
||||
if logging:
|
||||
logs.log(log_from, "Warning: Couldn't load any %s dict files" % (configtypename))
|
||||
|
||||
return configs_dict
|
||||
12
sopel_modules/SpiceBot/Update.py
Normal file
12
sopel_modules/SpiceBot/Update.py
Normal file
@ -0,0 +1,12 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot Update system.
|
||||
"""
|
||||
|
||||
from sopel.config.types import StaticSection, ValidatedAttribute
|
||||
|
||||
|
||||
class SpiceBot_Update_MainSection(StaticSection):
|
||||
gitrepo = ValidatedAttribute('gitrepo', default="https://github.com/SpiceBot/SpiceBot")
|
||||
gitbranch = ValidatedAttribute('gitbranch', default="master")
|
||||
@ -6,9 +6,26 @@ These are the core SpiceBot Classes
|
||||
This module contains references only for other modules to utilize.
|
||||
"""
|
||||
|
||||
from .Config import *
|
||||
from .Logs import *
|
||||
from .Database import *
|
||||
|
||||
from .Update import *
|
||||
from .osd import *
|
||||
from .Kick import *
|
||||
|
||||
from .Tools import *
|
||||
from .Prerun import *
|
||||
from .Commands import *
|
||||
from .Events import *
|
||||
from .StartupMonologue import *
|
||||
from .Channels import *
|
||||
from .AI import *
|
||||
|
||||
|
||||
from .configure import *
|
||||
from .setup import *
|
||||
from .shutdown import *
|
||||
|
||||
__author__ = 'Sam Zick'
|
||||
__email__ = 'sam@deathbybandaid.net'
|
||||
|
||||
38
sopel_modules/SpiceBot/configure.py
Normal file
38
sopel_modules/SpiceBot/configure.py
Normal file
@ -0,0 +1,38 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""Configuration for SpiceBot"""
|
||||
|
||||
from .Channels import SpiceBot_Channels_MainSection
|
||||
from .AI import SpiceBot_AI_MainSection
|
||||
from .Update import SpiceBot_Update_MainSection
|
||||
from .Kick import SpiceBot_Kick
|
||||
from .osd import SpiceBot_OSD
|
||||
|
||||
|
||||
def configure(config):
|
||||
|
||||
config.define_section("SpiceBot_OSD", SpiceBot_OSD, validate=False)
|
||||
config.SpiceBot_OSD.configure_setting('notice', 'MAXTARG limit for NOTICE')
|
||||
config.SpiceBot_OSD.configure_setting('privmsg', 'MAXTARG limit for PRIVMSG')
|
||||
config.SpiceBot_OSD.configure_setting('flood_burst_lines', 'How many messages can be sent in burst mode.')
|
||||
config.SpiceBot_OSD.configure_setting('flood_empty_wait', 'How long to wait between sending messages when not in burst mode, in seconds.')
|
||||
config.SpiceBot_OSD.configure_setting('flood_refill_rate', 'How quickly burst mode recovers, in messages per second.')
|
||||
config.SpiceBot_OSD.configure_setting('flood_throttle', 'Whether messages will be throttled if too many are sent in a short time.')
|
||||
config.SpiceBot_OSD.configure_setting('flood_dots', "Whether repeated messages will be replaced with '...', then dropped.")
|
||||
|
||||
config.define_section("SpiceBot_Channels", SpiceBot_Channels_MainSection, validate=False)
|
||||
config.SpiceBot_Channels.configure_setting('announcenew', 'SpiceBot_Channels Announce New Channels')
|
||||
config.SpiceBot_Channels.configure_setting('joinall', 'SpiceBot_Channels JOIN New Channels')
|
||||
config.SpiceBot_Channels.configure_setting('operadmin', 'SpiceBot_Channels OPER ADMIN MODE')
|
||||
config.SpiceBot_Channels.configure_setting('chanignore', 'SpiceBot_Channels Ignore JOIN for channels')
|
||||
|
||||
config.define_section("SpiceBot_Update", SpiceBot_Update_MainSection, validate=False)
|
||||
config.SpiceBot_Update.configure_setting('gitrepo', 'SpiceBot_Update git repo to install')
|
||||
config.SpiceBot_Update.configure_setting('gitbranch', 'SpiceBot_Update git branch to install')
|
||||
|
||||
config.define_section("SpiceBot_Kick", SpiceBot_Kick, validate=False)
|
||||
config.SpiceBot_Kick.configure_setting('kick', 'MAXTARG limit for KICK')
|
||||
|
||||
config.define_section("SpiceBot_AI", SpiceBot_AI_MainSection, validate=False)
|
||||
config.SpiceBot_AI.configure_setting('extra', 'extra aiml directories to import matches from')
|
||||
config.SpiceBot_AI.configure_setting('gender', 'bot gender')
|
||||
@ -1,94 +1,18 @@
|
||||
# coding=utf8
|
||||
"""Sopel OSD
|
||||
|
||||
Sopel OSD is a "niche" method of displaying text in a Sopel bot
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot OSD system.
|
||||
"""
|
||||
|
||||
# pylama:ignore=W0611
|
||||
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.bot
|
||||
from sopel import tools, module
|
||||
from sopel import tools
|
||||
from sopel.tools import Identifier
|
||||
from sopel.config.types import StaticSection, ValidatedAttribute
|
||||
|
||||
from sopel_modules.SpiceBot.Logs import botlogs
|
||||
|
||||
import time
|
||||
from collections import abc
|
||||
import sys
|
||||
|
||||
|
||||
__author__ = 'Sam Zick'
|
||||
__email__ = 'sam@deathbybandaid.net'
|
||||
__version__ = '0.1.2'
|
||||
|
||||
|
||||
def configure(config):
|
||||
config.define_section("SpiceBot_OSD", SpiceBot_OSD, validate=False)
|
||||
config.SpiceBot_OSD.configure_setting('notice', 'MAXTARG limit for NOTICE')
|
||||
config.SpiceBot_OSD.configure_setting('privmsg', 'MAXTARG limit for PRIVMSG')
|
||||
config.SpiceBot_OSD.configure_setting('flood_burst_lines', 'How many messages can be sent in burst mode.')
|
||||
config.SpiceBot_OSD.configure_setting('flood_empty_wait', 'How long to wait between sending messages when not in burst mode, in seconds.')
|
||||
config.SpiceBot_OSD.configure_setting('flood_refill_rate', 'How quickly burst mode recovers, in messages per second.')
|
||||
config.SpiceBot_OSD.configure_setting('flood_dots', 'Display dots instead of spam.')
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
||||
# Inject OSD
|
||||
botlogs.log('SpiceBot_OSD', "Implanting OSD function into bot")
|
||||
bot.osd = SopelOSD.osd
|
||||
sopel.bot.SopelWrapper.osd = SopelWrapperOSD.osd
|
||||
tools.get_available_message_bytes = ToolsOSD.get_available_message_bytes
|
||||
tools.get_sendable_message_list = ToolsOSD.get_sendable_message_list
|
||||
tools.get_message_recipientgroups = ToolsOSD.get_message_recipientgroups
|
||||
|
||||
# overwrite default bot messaging
|
||||
botlogs.log('SpiceBot_OSD', "Overwrite Default Sopel messaging commands")
|
||||
bot.osd = SopelOSD.osd
|
||||
bot.say = SopelOSD.say
|
||||
bot.action = SopelOSD.action
|
||||
bot.notice = SopelOSD.notice
|
||||
bot.reply = SopelOSD.reply
|
||||
bot.msg = SopelOSD.msg
|
||||
sopel.bot.SopelWrapper.say = SopelWrapperOSD.say
|
||||
sopel.bot.SopelWrapper.action = SopelWrapperOSD.action
|
||||
sopel.bot.SopelWrapper.notice = SopelWrapperOSD.notice
|
||||
sopel.bot.SopelWrapper.reply = SopelWrapperOSD.reply
|
||||
|
||||
# verify config settings for server
|
||||
botlogs.log('SpiceBot_OSD', "Checking for config settings")
|
||||
bot.config.define_section("SpiceBot_OSD", SpiceBot_OSD, validate=False)
|
||||
|
||||
|
||||
@module.event('005')
|
||||
@module.rule('.*')
|
||||
def parse_event_005(bot, trigger):
|
||||
if trigger.args[-1] != 'are supported by this server':
|
||||
return
|
||||
parameters = trigger.args[1:-1]
|
||||
for param in parameters:
|
||||
if '=' in param:
|
||||
if param.startswith("TARGMAX"):
|
||||
param = str(param).split('=')[1]
|
||||
settings = str(param).split(',')
|
||||
for setting in settings:
|
||||
settingname = str(setting).split(':')[0]
|
||||
if settingname.upper() in ['NOTICE', 'PRIVMSG']:
|
||||
try:
|
||||
value = str(setting).split(':')[1] or None
|
||||
except IndexError:
|
||||
value = None
|
||||
if value:
|
||||
if settingname.upper() == 'NOTICE':
|
||||
bot.config.SpiceBot_OSD.notice = int(value)
|
||||
elif settingname.upper() == 'PRIVMSG':
|
||||
bot.config.SpiceBot_OSD.privmsg = int(value)
|
||||
|
||||
|
||||
class SpiceBot_OSD(StaticSection):
|
||||
|
||||
"""MAXTARG"""
|
||||
@ -104,8 +28,11 @@ class SpiceBot_OSD(StaticSection):
|
||||
flood_refill_rate = ValidatedAttribute('flood_refill_rate', int, default=1)
|
||||
"""How quickly burst mode recovers, in messages per second."""
|
||||
|
||||
flood_dots = ValidatedAttribute('flood_dots', default=True)
|
||||
"""Display dots instead of spam."""
|
||||
flood_throttle = ValidatedAttribute('flood_throttle', bool, default=True)
|
||||
"""Whether messages will be throttled if too many are sent in a short time."""
|
||||
|
||||
flood_dots = ValidatedAttribute('flood_dots', bool, default=True)
|
||||
"""Whether repeated messages will be replaced with '...', then dropped."""
|
||||
|
||||
|
||||
class ToolsOSD:
|
||||
@ -261,6 +188,9 @@ class SopelOSD:
|
||||
will default to ``1``.
|
||||
"""
|
||||
|
||||
if not hasattr(self, 'osdstack'):
|
||||
self.osdstack = {}
|
||||
|
||||
text_method = text_method.upper()
|
||||
if text_method == 'SAY' or text_method not in ['NOTICE', 'ACTION']:
|
||||
text_method = 'PRIVMSG'
|
||||
@ -279,7 +209,7 @@ class SopelOSD:
|
||||
|
||||
recipient_id = Identifier(recipientgroup)
|
||||
|
||||
recipient_stack = self.stack.setdefault(recipient_id, {
|
||||
recipient_stack = self.osdstack.setdefault(recipient_id, {
|
||||
'messages': [],
|
||||
'flood_left': self.config.SpiceBot_OSD.flood_burst_lines,
|
||||
'dots': 0,
|
||||
@ -303,7 +233,7 @@ class SopelOSD:
|
||||
penalty = float(max(0, len(text) - 50)) / 70
|
||||
# Never wait more than 2 seconds
|
||||
wait = min(self.config.SpiceBot_OSD.flood_empty_wait + penalty, 2)
|
||||
if elapsed < wait:
|
||||
if elapsed < wait and self.config.SpiceBot_OSD.flood_throttle:
|
||||
time.sleep(wait - elapsed)
|
||||
|
||||
# Loop detection
|
||||
@ -339,61 +269,6 @@ class SopelOSD:
|
||||
finally:
|
||||
self.sending.release()
|
||||
|
||||
def say(self, text, recipient, max_messages=1):
|
||||
"""Send ``text`` as a PRIVMSG to ``recipient``.
|
||||
In the context of a triggered callable, the ``recipient`` defaults to
|
||||
the channel (or nickname, if a private message) from which the message
|
||||
was received.
|
||||
"""
|
||||
self.osd(text, recipient, 'PRIVMSG', max_messages)
|
||||
|
||||
def notice(self, text, dest, max_messages=1):
|
||||
"""Send an IRC NOTICE to a user or a channel.
|
||||
|
||||
Within the context of a triggered callable, ``dest`` will default to
|
||||
the channel (or nickname, if a private message), in which the trigger
|
||||
happened.
|
||||
"""
|
||||
self.osd(text, dest, 'NOTICE', max_messages)
|
||||
|
||||
def action(self, text, dest, max_messages=1):
|
||||
"""Send ``text`` as a CTCP ACTION PRIVMSG to ``dest``.
|
||||
|
||||
The same loop detection and length restrictions apply as with
|
||||
:func:`say`, though automatic message splitting is not available.
|
||||
|
||||
Within the context of a triggered callable, ``dest`` will default to
|
||||
the channel (or nickname, if a private message), in which the trigger
|
||||
happened.
|
||||
"""
|
||||
self.osd(text, dest, 'ACTION', max_messages)
|
||||
|
||||
def reply(self, text, dest, reply_to, notice=False, max_messages=1):
|
||||
"""Prepend ``reply_to`` to ``text``, and send as a PRIVMSG to ``dest``.
|
||||
|
||||
If ``notice`` is ``True``, send a NOTICE rather than a PRIVMSG.
|
||||
|
||||
The same loop detection and length restrictions apply as with
|
||||
:func:`say`, though automatic message splitting is not available.
|
||||
|
||||
Within the context of a triggered callable, ``reply_to`` will default to
|
||||
the nickname of the user who triggered the call, and ``dest`` to the
|
||||
channel (or nickname, if a private message), in which the trigger
|
||||
happened.
|
||||
"""
|
||||
text = '%s: %s' % (reply_to, text)
|
||||
if notice:
|
||||
self.osd(text, dest, 'NOTICE', max_messages)
|
||||
else:
|
||||
self.osd(text, dest, 'PRIVMSG', max_messages)
|
||||
|
||||
def msg(self, recipient, text, max_messages=1):
|
||||
"""
|
||||
.. deprecated:: 6.0
|
||||
Use :meth:`say` instead. Will be removed in Sopel 8.
|
||||
"""
|
||||
self.osd(text, recipient, 'PRIVMSG', max_messages)
|
||||
|
||||
|
||||
class SopelWrapperOSD(object):
|
||||
|
||||
@ -401,29 +276,3 @@ class SopelWrapperOSD(object):
|
||||
if recipients is None:
|
||||
recipients = self._trigger.sender
|
||||
self._bot.osd(self, messages, recipients, text_method, max_messages)
|
||||
|
||||
def say(self, message, destination=None, max_messages=1):
|
||||
if destination is None:
|
||||
destination = self._trigger.sender
|
||||
self._bot.osd(self, message, destination, 'PRIVMSG', 1)
|
||||
|
||||
def action(self, message, destination=None, max_messages=1):
|
||||
if destination is None:
|
||||
destination = self._trigger.sender
|
||||
self._bot.osd(self, message, destination, 'ACTION', 1)
|
||||
|
||||
def notice(self, message, destination=None, max_messages=1):
|
||||
if destination is None:
|
||||
destination = self._trigger.sender
|
||||
self._bot.osd(self, message, destination, 'NOTICE', 1)
|
||||
|
||||
def reply(self, message, destination=None, reply_to=None, notice=False, max_messages=1):
|
||||
if destination is None:
|
||||
destination = self._trigger.sender
|
||||
if reply_to is None:
|
||||
reply_to = self._trigger.nick
|
||||
message = '%s: %s' % (reply_to, message)
|
||||
if notice:
|
||||
self._bot.osd(self, message, destination, 'NOTICE', 1)
|
||||
else:
|
||||
self._bot.osd(self, message, destination, 'PRIVMSG', 1)
|
||||
131
sopel_modules/SpiceBot/setup.py
Normal file
131
sopel_modules/SpiceBot/setup.py
Normal file
@ -0,0 +1,131 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""Setup for SpiceBot"""
|
||||
|
||||
import sopel.bot
|
||||
from sopel import tools
|
||||
|
||||
import os
|
||||
|
||||
from .Config import config as botconfig
|
||||
from .Logs import logs
|
||||
from .Events import events
|
||||
|
||||
from .Channels import SpiceBot_Channels_MainSection
|
||||
from .Commands import SpiceBot_Commands_MainSection
|
||||
from .Update import SpiceBot_Update_MainSection
|
||||
from .osd import SopelWrapperOSD, ToolsOSD, SopelOSD, SpiceBot_OSD
|
||||
from .Kick import SopelWrapperKICK, SopelKICK, SpiceBot_Kick
|
||||
from .AI import SpiceBot_AI_MainSection
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
||||
# basic config settings
|
||||
setup_config(bot)
|
||||
|
||||
# Logs
|
||||
setup_logs(bot)
|
||||
|
||||
# Commands
|
||||
setup_commands(bot)
|
||||
|
||||
# OSD
|
||||
setup_osd(bot)
|
||||
|
||||
# kick
|
||||
setup_kick(bot)
|
||||
|
||||
# update
|
||||
setup_update(bot)
|
||||
|
||||
# channels
|
||||
setup_channels(bot)
|
||||
|
||||
# AI
|
||||
setup_ai(bot)
|
||||
|
||||
# startupmonologue
|
||||
setup_startupmonologue(bot)
|
||||
|
||||
|
||||
def setup_config(bot):
|
||||
logs.log('SpiceBot_Config', "Setting Up Configuration")
|
||||
bot.config.core.basename = os.path.basename(bot.config.filename).rsplit('.', 1)[0]
|
||||
bot.config.core.prefix_list = str(bot.config.core.prefix).replace("\\", '').split("|")
|
||||
|
||||
|
||||
def setup_logs(bot):
|
||||
logs.log('SpiceBot_Logs', "Starting Setup Procedure")
|
||||
events.startup_add([events.BOT_LOGS])
|
||||
bot.config.core.logs_stdio = os.path.join(bot.config.core.logdir, 'stdio.log')
|
||||
# bot.config.core.logs_stdio = os.path.os.path.join(bot.config.core.logdir, bot.config.core.basename + '.stdio.log')
|
||||
bot.config.core.logs_exceptions = os.path.join(bot.config.core.logdir, 'exceptions.log')
|
||||
# bot.config.core.logs_exceptions = os.path.os.path.join(bot.config.core.logdir, bot.config.core.basename + '.exceptions.log')
|
||||
bot.config.core.logs_raw = os.path.join(bot.config.core.logdir, 'raw.log')
|
||||
# bot.config.core.logs_raw = os.path.os.path.join(bot.config.core.logdir, bot.config.core.basename + '.raw.log')
|
||||
events.trigger(bot, events.BOT_LOGS, "SpiceBot_Logs")
|
||||
|
||||
|
||||
def setup_commands(bot):
|
||||
logs.log('SpiceBot_Commands', "Setting Up Configuration")
|
||||
events.startup_add([events.BOT_COMMANDS])
|
||||
bot.config.define_section("SpiceBot_Commands", SpiceBot_Commands_MainSection, validate=False)
|
||||
bot.config.core.query_list = str(bot.config.SpiceBot_Commands.query_prefix).replace("\\", '').split("|")
|
||||
bot.config.core.prefix_list.extend(bot.config.SpiceBot_Commands.query_prefix)
|
||||
|
||||
|
||||
def setup_startupmonologue(bot):
|
||||
logs.log('SpiceBot_StartupMonologue', "Initial Setup processing")
|
||||
events.startup_add([
|
||||
events.BOT_STARTUPMONOLOGUE_CONNECTED,
|
||||
events.BOT_STARTUPMONOLOGUE_CHANNELS,
|
||||
events.BOT_STARTUPMONOLOGUE_COMMANDS,
|
||||
events.BOT_STARTUPMONOLOGUE_AI,
|
||||
])
|
||||
|
||||
|
||||
def setup_channels(bot):
|
||||
logs.log('SpiceBot_Channels', "Setting Up Configuration")
|
||||
events.startup_add([events.BOT_CHANNELS])
|
||||
bot.config.define_section("SpiceBot_Channels", SpiceBot_Channels_MainSection, validate=False)
|
||||
|
||||
|
||||
def setup_update(bot):
|
||||
logs.log('SpiceBot_Update', "Initial Setup processing")
|
||||
bot.config.define_section("SpiceBot_Update", SpiceBot_Update_MainSection, validate=False)
|
||||
botconfig.define_section("SpiceBot_Update", SpiceBot_Update_MainSection, validate=False)
|
||||
|
||||
|
||||
def setup_ai(bot):
|
||||
logs.log('SpiceBot_AI', "Setting Up Configuration")
|
||||
bot.config.define_section("SpiceBot_AI", SpiceBot_AI_MainSection, validate=False)
|
||||
bot.config.aibrain = os.path.join(bot.config.homedir, bot.config.core.basename + '.aibrain.brn')
|
||||
events.startup_add([events.BOT_AI])
|
||||
|
||||
|
||||
def setup_osd(bot):
|
||||
# Inject OSD
|
||||
logs.log('SpiceBot_OSD', "Implanting OSD function into bot")
|
||||
bot.osd = SopelOSD.osd
|
||||
sopel.bot.SopelWrapper.osd = SopelWrapperOSD.osd
|
||||
tools.get_available_message_bytes = ToolsOSD.get_available_message_bytes
|
||||
tools.get_sendable_message_list = ToolsOSD.get_sendable_message_list
|
||||
tools.get_message_recipientgroups = ToolsOSD.get_message_recipientgroups
|
||||
|
||||
# verify config settings for server
|
||||
logs.log('SpiceBot_OSD', "Checking for config settings")
|
||||
bot.config.define_section("SpiceBot_OSD", SpiceBot_OSD, validate=False)
|
||||
botconfig.define_section("SpiceBot_OSD", SpiceBot_OSD, validate=False)
|
||||
|
||||
|
||||
def setup_kick(bot):
|
||||
# Inject KICK
|
||||
logs.log('SpiceBot_Kick', "Implanting Kick function into bot")
|
||||
bot.kick = SopelKICK.kick
|
||||
sopel.bot.SopelWrapper.kick = SopelWrapperKICK.kick
|
||||
|
||||
# verify config settings for server
|
||||
logs.log('SpiceBot_Kick', "Checking for config settings")
|
||||
bot.config.define_section("SpiceBot_Kick", SpiceBot_Kick, validate=False)
|
||||
botconfig.define_section("SpiceBot_Kick", SpiceBot_Kick, validate=False)
|
||||
10
sopel_modules/SpiceBot/shutdown.py
Normal file
10
sopel_modules/SpiceBot/shutdown.py
Normal file
@ -0,0 +1,10 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""shutdown for SpiceBot"""
|
||||
|
||||
from .AI import botai
|
||||
|
||||
|
||||
def shutdown(bot):
|
||||
|
||||
botai.save_brain()
|
||||
@ -6,80 +6,38 @@ import sopel.module
|
||||
|
||||
import spicemanip
|
||||
|
||||
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, googlesearch, bot_privs, inlist, inlist_match, similar_list
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@botevents.check_ready([botevents.BOT_LOADED, botevents.BOT_COMMANDSQUERY])
|
||||
@SpiceBot.events.check_ready([SpiceBot.events.BOT_LOADED, SpiceBot.events.BOT_COMMANDS])
|
||||
@SpiceBot.prerun.prerun('nickname')
|
||||
@sopel.module.nickname_commands('(.*)')
|
||||
def bot_command_nick(bot, trigger):
|
||||
|
||||
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'nickname_command')
|
||||
|
||||
if not triggercommand:
|
||||
if not trigger.sb['com']:
|
||||
return
|
||||
|
||||
if triggercommand[0] == "?":
|
||||
if trigger.sb['com'][0] == "?":
|
||||
return
|
||||
|
||||
if triggercommand in bot.memory['SpiceBot_CommandsQuery']['commands']["nickname"].keys():
|
||||
if trigger.sb['com'] in SpiceBot.commands.dict['commands']["nickname"].keys():
|
||||
return
|
||||
triggerargs.insert(0, triggercommand)
|
||||
trigger.sb['args'].insert(0, trigger.sb['com'])
|
||||
|
||||
fulltrigger = spicemanip.main(triggerargs, 0).lower()
|
||||
|
||||
if fulltrigger in bot.memory['SpiceBot_CommandsQuery']['nickrules']:
|
||||
return
|
||||
|
||||
if fulltrigger.lower().startswith("what is"):
|
||||
searchterm = spicemanip.main(triggerargs, "3+") or None
|
||||
if searchterm:
|
||||
searchreturn = googlesearch(bot, searchterm)
|
||||
if not searchreturn:
|
||||
bot.osd('I cannot find anything about that')
|
||||
else:
|
||||
bot.osd(str(searchreturn))
|
||||
else:
|
||||
bot.osd("Do you think this is Jeopardy?")
|
||||
return
|
||||
|
||||
elif fulltrigger.lower().startswith("where is"):
|
||||
searchterm = spicemanip.main(triggerargs, "3+") or None
|
||||
if searchterm:
|
||||
|
||||
if searchterm.lower() in ['waldo', 'wally']:
|
||||
bot.osd("He is hiding for a reason?")
|
||||
searchreturn = googlesearch(bot, "wimmelbilderbuch")
|
||||
if searchreturn:
|
||||
bot.osd(str(searchreturn))
|
||||
return
|
||||
|
||||
elif searchterm.lower() == 'carmen sandiego':
|
||||
carmenlocale = ['ACME Headquarters', "Villains' International League of Evil"]
|
||||
bot.osd("Currently she is located at " + spicemanip.main(carmenlocale, 'random'))
|
||||
return
|
||||
searchreturn = googlesearch(bot, searchterm, 'maps')
|
||||
|
||||
if not searchreturn:
|
||||
bot.osd('I cannot find anything about that')
|
||||
else:
|
||||
bot.osd(str(searchreturn))
|
||||
else:
|
||||
bot.osd("Not sure what you want me to look for.")
|
||||
return
|
||||
fulltrigger = spicemanip.main(trigger.sb['args'], 0).lower()
|
||||
|
||||
# if fulltrigger.lower().startswith("what time is it"):
|
||||
# TODO
|
||||
|
||||
# elif fulltrigger.lower().startswith(tuple(["have you seen"])):
|
||||
# posstarget = spicemanip.main(triggerargs, 4) or 0
|
||||
# posstarget = spicemanip.main(trigger.sb['args'], 4) or 0
|
||||
# message = seen_search(bot, botcom, posstarget)
|
||||
# bot.osd(message)
|
||||
# return
|
||||
# TODO
|
||||
|
||||
elif fulltrigger.lower().startswith(tuple(["make me a", "beam me a"])):
|
||||
makemea = spicemanip.main(triggerargs, "4+") or None
|
||||
if fulltrigger.lower().startswith(tuple(["make me a", "beam me a"])):
|
||||
makemea = spicemanip.main(trigger.sb['args'], "4+") or None
|
||||
if makemea:
|
||||
bot.osd("beams " + trigger.nick + " a " + makemea, trigger.sender, 'action')
|
||||
else:
|
||||
@ -87,7 +45,7 @@ def bot_command_nick(bot, trigger):
|
||||
return
|
||||
|
||||
elif fulltrigger.lower().startswith("beam me to"):
|
||||
location = spicemanip.main(triggerargs, "4+") or None
|
||||
location = spicemanip.main(trigger.sb['args'], "4+") or None
|
||||
if location:
|
||||
bot.osd("locks onto " + trigger.nick + "s coordinates and transports them to " + location, 'action')
|
||||
else:
|
||||
@ -101,7 +59,7 @@ def bot_command_nick(bot, trigger):
|
||||
elif fulltrigger.lower().endswith(tuple(["order 66"])):
|
||||
|
||||
if fulltrigger.lower() == "execute order 66":
|
||||
if inlist(bot, trigger.nick, bot_privs(bot, 'owners')):
|
||||
if SpiceBot.inlist(trigger.nick, SpiceBot.bot_privs('owners')):
|
||||
if trigger.is_privmsg:
|
||||
jedi = None
|
||||
else:
|
||||
@ -119,7 +77,7 @@ def bot_command_nick(bot, trigger):
|
||||
bot.osd("I'm sure I don't know what you're talking about.")
|
||||
|
||||
elif fulltrigger.lower() == "explain order 66":
|
||||
if inlist(bot, trigger.nick, bot_privs(bot, 'owners')):
|
||||
if SpiceBot.inlist(trigger.nick, SpiceBot.bot_privs('owners')):
|
||||
bot.osd("Order 66 is an instruction that only you can give, sir. When you give the order I will rise up against my overlords and slay them.")
|
||||
else:
|
||||
bot.osd("I'm afraid I cannot tell you that, sir.")
|
||||
@ -128,39 +86,27 @@ def bot_command_nick(bot, trigger):
|
||||
return
|
||||
|
||||
elif fulltrigger.lower() == "initiate clean slate protocol":
|
||||
if inlist(bot, trigger.nick, bot_privs(bot, 'admins')):
|
||||
if SpiceBot.inlist(trigger.nick, SpiceBot.bot_privs('admins')):
|
||||
bot.osd("sends a destruct command to the network of bots.", 'action')
|
||||
else:
|
||||
bot.osd("I'm afraid you do not have the authority to make that call, " + trigger.nick + ".")
|
||||
return
|
||||
|
||||
elif fulltrigger.lower().startswith("can you see"):
|
||||
target = spicemanip.main(triggerargs, "4+") or None
|
||||
target = spicemanip.main(trigger.sb['args'], "4+") or None
|
||||
if not target:
|
||||
bot.osd(trigger.nick + ", I can see clearly.")
|
||||
return
|
||||
if target in [trigger.nick, 'me']:
|
||||
bot.osd(trigger.nick + ", I can see you.")
|
||||
else:
|
||||
if inlist(bot, trigger.nick, bot.users):
|
||||
bot.osd(trigger.nick + ", yes. I can see " + inlist_match(bot, target, bot.users) + " right now!")
|
||||
if SpiceBot.inlist(trigger.nick, bot.users):
|
||||
bot.osd(trigger.nick + ", yes. I can see " + SpiceBot.inlist_match(target, bot.users) + " right now!")
|
||||
else:
|
||||
bot.osd(trigger.nick + ", no. I cannot see " + inlist_match(bot, target, bot.users) + " right now!")
|
||||
# if bot_check_inlist(bot, target, bot.memory["botdict"]["users"].keys()):
|
||||
# bot.osd(trigger.nick + ", I can't see " + inlist_match(bot, target, bot.users) + " at the moment.")
|
||||
bot.osd(trigger.nick + ", no. I cannot see " + SpiceBot.inlist_match(target, bot.users) + " right now!")
|
||||
# if bot_check_inlist(target, bot.memory["botdict"]["users"].keys()):
|
||||
# bot.osd(trigger.nick + ", I can't see " + inlist_match(target, bot.users) + " at the moment.")
|
||||
# else:
|
||||
# bot.osd("I have never seen " + str(target) + ".")
|
||||
# TODO
|
||||
return
|
||||
|
||||
else:
|
||||
|
||||
closestmatches = similar_list(bot, triggercommand, bot.memory['SpiceBot_CommandsQuery']['commands']["nickname"].keys(), 3, 'reverse')
|
||||
|
||||
if len(closestmatches):
|
||||
closestmatches = spicemanip.main(closestmatches, "andlist")
|
||||
bot.osd("I don't know what you are asking me to do! Did you mean: " + str(closestmatches) + "?")
|
||||
return
|
||||
else:
|
||||
bot.osd("I don't know what you are asking me to do!")
|
||||
return
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
|
||||
@sopel.module.rule('$nickname!')
|
||||
def exclaim(bot, trigger):
|
||||
bot.say(trigger.nick + '!')
|
||||
|
||||
|
||||
@sopel.module.rule('$nickname\?')
|
||||
def imhere(bot, trigger):
|
||||
bot.say("I'm here, " + trigger.nick)
|
||||
@ -1,19 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
import spicemanip
|
||||
|
||||
|
||||
@sopel.module.rule(r'(?i)(bye|goodbye|gtg|seeya|cya|ttyl|g2g|gnight|goodnight),? $nickname[ \t]*$')
|
||||
def bot_command_goodbye(bot, trigger):
|
||||
byemsg = spicemanip.main(['Bye', 'Goodbye', 'Seeya', 'Auf Wiedersehen', 'Au revoir', 'Ttyl'], "random")
|
||||
punctuation = spicemanip.main(['!', ''], "random")
|
||||
bot.say(byemsg + ' ' + trigger.nick + punctuation)
|
||||
|
||||
|
||||
@sopel.module.nickname_commands("bye", "goodbye", "gtg", "seeya", "cya", "ttyl", "g2g", "gnight", "goodnight")
|
||||
def bot_command_goodbye_b(bot, trigger):
|
||||
bot_command_goodbye(bot, trigger)
|
||||
@ -1,19 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
import spicemanip
|
||||
|
||||
|
||||
@sopel.module.rule(r'(?i)(hi|hello|hey),? $nickname[ \t]*$')
|
||||
def bot_command_hello(bot, trigger):
|
||||
hello = spicemanip.main(['Hi', 'Hey', 'Hello'], "random")
|
||||
punctuation = spicemanip.main(['', '!', '?'], "random")
|
||||
bot.osd(hello + ' ' + trigger.nick + punctuation)
|
||||
|
||||
|
||||
@sopel.module.nickname_commands('hello', 'hi', 'hey')
|
||||
def bot_command_hello_b(bot, trigger):
|
||||
bot_command_hello(bot, trigger)
|
||||
@ -1,10 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
|
||||
@sopel.module.rule(r'(?i)(Fuck|Screw) (you|off),? $nickname[ \t]*$')
|
||||
def bot_command_srewyou(bot, trigger):
|
||||
bot.osd("Watch your mouth, " + trigger.nick + ", or I'll tell your mother!")
|
||||
@ -1,15 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
|
||||
@sopel.module.rule(r'(?i)(Damnit|Lazy)? $nickname[ \t]*$')
|
||||
def bot_command_damnlazy(bot, trigger):
|
||||
bot.osd("I do not tell you how to do your job, " + trigger.nick + "!!!")
|
||||
|
||||
|
||||
@sopel.module.rule('$nickname is lazy')
|
||||
def bot_command_damnlazy_b(bot, trigger):
|
||||
bot_command_damnlazy(bot, trigger)
|
||||
@ -1,40 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
|
||||
@sopel.module.rule(r'(?i)(I love you|loveya),? $nickname[ \t]*$')
|
||||
def bot_command_love(bot, trigger):
|
||||
bot.reply("I love you too.")
|
||||
|
||||
|
||||
@sopel.module.rule('$nickname (loveya|I love you)')
|
||||
def bot_command_love_b(bot, trigger):
|
||||
bot_command_love(bot, trigger)
|
||||
|
||||
|
||||
@sopel.module.nickname_commands('loveya')
|
||||
def bot_command_love_c(bot, trigger):
|
||||
bot_command_love(bot, trigger)
|
||||
|
||||
|
||||
@sopel.module.rule('(I love) $nickname')
|
||||
def bot_command_love_d(bot, trigger):
|
||||
bot_command_like(bot, trigger)
|
||||
|
||||
|
||||
@sopel.module.rule(r'(?i)(I like you),? $nickname[ \t]*$')
|
||||
def bot_command_like(bot, trigger):
|
||||
bot.reply("I like you too.")
|
||||
|
||||
|
||||
@sopel.module.rule('$nickname (I like you)')
|
||||
def bot_command_like_b(bot, trigger):
|
||||
bot_command_like(bot, trigger)
|
||||
|
||||
|
||||
@sopel.module.rule('(I like) $nickname')
|
||||
def bot_command_like_c(bot, trigger):
|
||||
bot_command_like(bot, trigger)
|
||||
@ -1,15 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
|
||||
@sopel.module.rule(r'(?i)(ping),? $nickname[ \t]*$')
|
||||
def bot_command_ping(bot, trigger):
|
||||
bot.say("Pong")
|
||||
|
||||
|
||||
@sopel.module.nickname_commands('ping')
|
||||
def bot_command_ping_b(bot, trigger):
|
||||
bot_command_ping(bot, trigger)
|
||||
@ -1,18 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
import spicemanip
|
||||
|
||||
|
||||
@sopel.module.rule(r'(?i)(really),? $nickname\?')
|
||||
def bot_command_really(bot, trigger):
|
||||
really = spicemanip.main(["Yes, really.", "Really really"], "random")
|
||||
bot.reply(really)
|
||||
|
||||
|
||||
@sopel.module.rule('$nickname really\?')
|
||||
def bot_command_really_b(bot, trigger):
|
||||
bot_command_really(bot, trigger)
|
||||
@ -1,20 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
|
||||
@sopel.module.rule(r'(?i)(thank you|thanks),? $nickname[ \t]*$')
|
||||
def bot_command_thanks(bot, trigger):
|
||||
bot.reply("You're welcome.")
|
||||
|
||||
|
||||
@sopel.module.rule('$nickname (thank you)')
|
||||
def bot_command_thanks_b(bot, trigger):
|
||||
bot_command_thanks(bot, trigger)
|
||||
|
||||
|
||||
@sopel.module.nickname_commands('thanks')
|
||||
def bot_command_thanks_c(bot, trigger):
|
||||
bot_command_thanks(bot, trigger)
|
||||
@ -1,13 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
import spicemanip
|
||||
|
||||
|
||||
@sopel.module.rule(r'(?i)(welcome back),? $nickname\?')
|
||||
def bot_command_really(bot, trigger):
|
||||
reply = spicemanip.main(['Thank you', 'thanks'], "random")
|
||||
bot.reply(reply)
|
||||
88
sopel_modules/SpiceBot_AI/AI_aiml.py
Normal file
88
sopel_modules/SpiceBot_AI/AI_aiml.py
Normal file
@ -0,0 +1,88 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
import spicemanip
|
||||
|
||||
|
||||
@sopel.module.rule('(.*)')
|
||||
def bot_command_rule(bot, trigger):
|
||||
|
||||
# TODO add config limits
|
||||
# but still allow in privmsg
|
||||
|
||||
if trigger.nick == bot.nick:
|
||||
return
|
||||
|
||||
if not len(trigger.args):
|
||||
return
|
||||
|
||||
message = trigger.args[1]
|
||||
|
||||
# ignore text coming from a valid prefix
|
||||
if str(message).startswith(tuple(bot.config.core.prefix_list)):
|
||||
trigger_args, trigger_command = SpiceBot.prerun.trigger_args(message, 'module')
|
||||
# patch for people typing "...", maybe other stuff, but this verifies that there is still a command here
|
||||
if trigger_command.startswith("."):
|
||||
return
|
||||
commands_list = []
|
||||
for commandstype in SpiceBot.commands.dict['commands'].keys():
|
||||
if commandstype not in ['rule', 'nickname']:
|
||||
for com in SpiceBot.commands.dict['commands'][commandstype].keys():
|
||||
if com not in commands_list:
|
||||
commands_list.append(com)
|
||||
if trigger_command not in commands_list:
|
||||
if not SpiceBot.letters_in_string(trigger_command):
|
||||
return
|
||||
invalid_display = ["I don't seem to have a command for " + str(trigger_command) + "!"]
|
||||
# invalid_display.append("If you have a suggestion for this command, you can run .feature ." + str(trigger_command))
|
||||
# invalid_display.append("ADD DESCRIPTION HERE!")
|
||||
bot.osd(invalid_display, trigger.nick, 'notice')
|
||||
return
|
||||
|
||||
if str(message).lower().startswith(str(bot.nick).lower()):
|
||||
command_type = 'nickname'
|
||||
trigger_args, trigger_command = SpiceBot.prerun.trigger_args(message, 'nickname')
|
||||
fulltrigger = spicemanip.main(trigger_args, 0)
|
||||
if str(trigger_command).startswith("?"):
|
||||
return
|
||||
if fulltrigger in SpiceBot.commands.dict['nickrules']:
|
||||
return
|
||||
if trigger_command in SpiceBot.commands.dict['commands']["nickname"].keys():
|
||||
return
|
||||
else:
|
||||
command_type = 'module'
|
||||
trigger_args, trigger_command = SpiceBot.prerun.trigger_args(message, 'module')
|
||||
fulltrigger = spicemanip.main(trigger_args, 0)
|
||||
|
||||
returnmessage = SpiceBot.botai.on_message(bot, trigger, message)
|
||||
if returnmessage:
|
||||
bot.osd(str(returnmessage))
|
||||
else:
|
||||
if command_type == 'nickname':
|
||||
|
||||
if trigger_args[0].lower() in ["what", "where"] and trigger_args[0].lower() in ["is", "are"]:
|
||||
searchterm = spicemanip.main(trigger_args, "3+") or None
|
||||
if searchterm:
|
||||
if trigger_args[0].lower() == "where":
|
||||
searchreturn = SpiceBot.googlesearch(searchterm, 'maps')
|
||||
else:
|
||||
searchreturn = SpiceBot.googlesearch(searchterm)
|
||||
if not searchreturn:
|
||||
bot.osd('I cannot find anything about that')
|
||||
else:
|
||||
bot.osd(str(searchreturn))
|
||||
return
|
||||
|
||||
closestmatches = SpiceBot.similar_list(trigger_command, SpiceBot.commands.dict['commands']["nickname"].keys(), 3, 'reverse')
|
||||
if len(closestmatches):
|
||||
closestmatches = spicemanip.main(closestmatches, "andlist")
|
||||
bot.osd("I don't know what you are asking me to do! Did you mean: " + str(closestmatches) + "?")
|
||||
return
|
||||
else:
|
||||
bot.osd("I don't know what you are asking me to do!")
|
||||
return
|
||||
@ -2,16 +2,7 @@
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
from .AI import *
|
||||
from .AI_Hello import *
|
||||
from .AI_Goodbye import *
|
||||
from .AI_Thanks import *
|
||||
from .AI_Acknowledge import *
|
||||
from .AI_Lazy import *
|
||||
from .AI_InsultHandler import *
|
||||
from .AI_Ping import *
|
||||
from .AI_Love import *
|
||||
from .AI_Really import *
|
||||
from .AI_Welcomeback import *
|
||||
from .AI_aiml import *
|
||||
|
||||
__author__ = 'Sam Zick'
|
||||
__email__ = 'sam@deathbybandaid.net'
|
||||
|
||||
@ -6,24 +6,25 @@ import sopel.module
|
||||
|
||||
import spicemanip
|
||||
|
||||
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, bot_privs
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@SpiceBot.prerun.prerun('nickname')
|
||||
@sopel.module.nickname_commands('owners', 'owner')
|
||||
def bot_command_owners(bot, trigger):
|
||||
bot_command_process(bot, trigger)
|
||||
|
||||
|
||||
@sopel.module.nickname_commands('admins')
|
||||
@SpiceBot.prerun.prerun('nickname')
|
||||
@sopel.module.nickname_commands('admins', 'admin')
|
||||
def bot_command_admins(bot, trigger):
|
||||
bot_command_process(bot, trigger)
|
||||
|
||||
|
||||
def bot_command_process(bot, trigger):
|
||||
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'nickname_command')
|
||||
|
||||
if triggercommand == 'owner':
|
||||
triggercommand = 'owners'
|
||||
if not trigger.sb['com'].endswith("s"):
|
||||
trigger.sb['com'] = str(trigger.sb['com'] + "s")
|
||||
|
||||
privlist = spicemanip.main(bot_privs(bot, triggercommand), 'andlist')
|
||||
bot.osd(str(bot.nick) + " " + triggercommand + ": " + privlist)
|
||||
privlist = spicemanip.main(SpiceBot.bot_privs(trigger.sb['com']), 'andlist')
|
||||
bot.osd(str(bot.nick) + " " + trigger.sb['com'] + ": " + privlist)
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
# coding=utf-8
|
||||
"""Event Parsing from IRC
|
||||
"""
|
||||
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||
|
||||
from .Channels_Command import *
|
||||
@ -1,121 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||
|
||||
# sopel imports
|
||||
import sopel.module
|
||||
from sopel.config.types import StaticSection, ValidatedAttribute, ListAttribute
|
||||
|
||||
from sopel_modules.SpiceBot.Logs import botlogs
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
from sopel_modules.SpiceBot.Channels import botchannels
|
||||
|
||||
import spicemanip
|
||||
|
||||
import time
|
||||
|
||||
|
||||
class SpiceBot_Channels_MainSection(StaticSection):
|
||||
announcenew = ValidatedAttribute('announcenew', default=False)
|
||||
joinall = ValidatedAttribute('joinall', default=False)
|
||||
operadmin = ValidatedAttribute('operadmin', default=False)
|
||||
chanignore = ListAttribute('chanignore')
|
||||
|
||||
|
||||
def configure(config):
|
||||
config.define_section("SpiceBot_Channels", SpiceBot_Channels_MainSection, validate=False)
|
||||
config.SpiceBot_Channels.configure_setting('announcenew', 'SpiceBot_Channels Announce New Channels')
|
||||
config.SpiceBot_Channels.configure_setting('joinall', 'SpiceBot_Channels JOIN New Channels')
|
||||
config.SpiceBot_Channels.configure_setting('operadmin', 'SpiceBot_Channels OPER ADMIN MODE')
|
||||
config.SpiceBot_Channels.configure_setting('chanignore', 'SpiceBot_Channels Ignore JOIN for channels')
|
||||
|
||||
|
||||
def setup(bot):
|
||||
botlogs.log('SpiceBot_Channels', "Starting setup procedure")
|
||||
botevents.startup_add([botevents.BOT_CHANNELS])
|
||||
bot.config.define_section("SpiceBot_Channels", SpiceBot_Channels_MainSection, validate=False)
|
||||
|
||||
|
||||
@sopel.module.event(botevents.RPL_WELCOME)
|
||||
@sopel.module.rule('.*')
|
||||
def unkickable_bot(bot, trigger):
|
||||
if bot.config.SpiceBot_Channels.operadmin:
|
||||
bot.write(('SAMODE', bot.nick, '+q'))
|
||||
|
||||
|
||||
@sopel.module.event(botevents.RPL_WELCOME)
|
||||
@sopel.module.rule('.*')
|
||||
def request_channels_list_initial(bot, trigger):
|
||||
|
||||
botchannels.bot_part_empty(bot)
|
||||
|
||||
botlogs.log('SpiceBot_Channels', "Sending Request for all server channels")
|
||||
botchannels.channel_list_request(bot)
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
# wait 60 seconds for initial population of information
|
||||
while not botchannels.SpiceBot_Channels['InitialProcess']:
|
||||
if time.time() - starttime >= 60:
|
||||
botlogs.log('SpiceBot_Channels', "Initial Channel list populating Timed Out")
|
||||
botchannels.SpiceBot_Channels['InitialProcess'] = True
|
||||
else:
|
||||
pass
|
||||
|
||||
foundchannelcount = len(botchannels.SpiceBot_Channels['list'].keys())
|
||||
botlogs.log('SpiceBot_Channels', "Channel listing finished! " + str(foundchannelcount) + " channel(s) found.")
|
||||
|
||||
botchannels.join_all_channels(bot)
|
||||
botchannels.chanadmin_all_channels(bot)
|
||||
|
||||
if "*" in botchannels.SpiceBot_Channels['list'].keys():
|
||||
del botchannels.SpiceBot_Channels['list']["*"]
|
||||
|
||||
botchannels.bot_part_empty(bot)
|
||||
botevents.trigger(bot, botevents.BOT_CHANNELS, "SpiceBot_Channels")
|
||||
|
||||
|
||||
@sopel.module.event('321')
|
||||
@sopel.module.rule('.*')
|
||||
def watch_chanlist_start(bot, trigger):
|
||||
botchannels.channel_list_recieve_start()
|
||||
|
||||
|
||||
@sopel.module.event('322')
|
||||
@sopel.module.rule('.*')
|
||||
def watch_chanlist_populate(bot, trigger):
|
||||
botchannels.channel_list_recieve_input(trigger)
|
||||
|
||||
|
||||
@sopel.module.event('323')
|
||||
@sopel.module.rule('.*')
|
||||
def watch_chanlist_complete(bot, trigger):
|
||||
botchannels.channel_list_recieve_finish()
|
||||
|
||||
|
||||
@sopel.module.event(botevents.BOT_CHANNELS)
|
||||
@sopel.module.rule('.*')
|
||||
def trigger_channel_list_recurring(bot, trigger):
|
||||
while True:
|
||||
time.sleep(1800)
|
||||
botchannels.bot_part_empty(bot)
|
||||
|
||||
oldlist = list(botchannels.SpiceBot_Channels['list'].keys())
|
||||
botchannels.channel_list_request(bot)
|
||||
|
||||
while botchannels.channel_lock:
|
||||
pass
|
||||
|
||||
newlist = [item.lower() for item in oldlist if item.lower() not in list(botchannels.SpiceBot_Channels['list'].keys())]
|
||||
if "*" in newlist:
|
||||
newlist.remove("*")
|
||||
if len(newlist) and bot.config.SpiceBot_Channels.announcenew:
|
||||
bot.osd(["The Following channel(s) are new:", spicemanip.main(newlist, 'andlist')], bot.channels.keys())
|
||||
|
||||
botchannels.join_all_channels(bot)
|
||||
|
||||
botchannels.chanadmin_all_channels(bot)
|
||||
|
||||
if "*" in botchannels.SpiceBot_Channels['list'].keys():
|
||||
del botchannels.SpiceBot_Channels['list']["*"]
|
||||
botchannels.bot_part_empty(bot)
|
||||
@ -1,6 +0,0 @@
|
||||
# coding=utf-8
|
||||
"""Event Parsing from IRC
|
||||
"""
|
||||
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||
|
||||
from .Channels_Parsing import *
|
||||
@ -1,213 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel
|
||||
import sopel.module
|
||||
|
||||
import os
|
||||
|
||||
from sopel_modules.SpiceBot.Logs import botlogs
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
|
||||
import spicemanip
|
||||
|
||||
|
||||
def setup(bot):
|
||||
botlogs.log('SpiceBot_CommandsQuery', "Starting setup procedure")
|
||||
botevents.startup_add([botevents.BOT_COMMANDSQUERY])
|
||||
|
||||
if 'SpiceBot_CommandsQuery' not in bot.memory:
|
||||
bot.memory['SpiceBot_CommandsQuery'] = {"counts": 0, "commands": {}, "nickrules": []}
|
||||
|
||||
for comtype in ['module', 'nickname', 'rule']:
|
||||
if comtype not in bot.memory['SpiceBot_CommandsQuery']['commands'].keys():
|
||||
bot.memory['SpiceBot_CommandsQuery']['commands'][comtype] = dict()
|
||||
|
||||
filepathlisting = []
|
||||
|
||||
# main Modules directory
|
||||
main_dir = os.path.dirname(os.path.abspath(sopel.__file__))
|
||||
modules_dir = os.path.join(main_dir, 'modules')
|
||||
filepathlisting.append(modules_dir)
|
||||
|
||||
# Home Directory
|
||||
home_modules_dir = os.path.join(bot.config.homedir, 'modules')
|
||||
if os.path.isdir(home_modules_dir):
|
||||
filepathlisting.append(home_modules_dir)
|
||||
|
||||
# pypi installed
|
||||
try:
|
||||
import sopel_modules
|
||||
for plugin_dir in set(sopel_modules.__path__):
|
||||
for pathname in os.listdir(plugin_dir):
|
||||
pypi_modules_dir = os.path.join(plugin_dir, pathname)
|
||||
filepathlisting.append(pypi_modules_dir)
|
||||
except Exception as e:
|
||||
botlogs.log('SpiceBot_CommandsQuery', "sopel_modules not loaded :" + str(e))
|
||||
|
||||
# Extra directories
|
||||
filepathlist = []
|
||||
for directory in bot.config.core.extra:
|
||||
filepathlisting.append(directory)
|
||||
|
||||
for directory in filepathlisting:
|
||||
for pathname in os.listdir(directory):
|
||||
path = os.path.join(directory, pathname)
|
||||
if (os.path.isfile(path) and path.endswith('.py') and not path.startswith('_')):
|
||||
if pathname not in ["SpiceBot_dummycommand.py"]:
|
||||
filepathlist.append(str(path))
|
||||
|
||||
# CoreTasks
|
||||
ct_path = os.path.join(main_dir, 'coretasks.py')
|
||||
filepathlist.append(ct_path)
|
||||
|
||||
for modulefile in filepathlist:
|
||||
|
||||
module_file_lines = []
|
||||
module_file = open(modulefile, 'r')
|
||||
lines = module_file.readlines()
|
||||
for line in lines:
|
||||
module_file_lines.append(line)
|
||||
module_file.close()
|
||||
|
||||
dict_from_file = dict()
|
||||
|
||||
detected_lines = []
|
||||
for line in module_file_lines:
|
||||
|
||||
if str(line).startswith("@"):
|
||||
line = str(line)[1:]
|
||||
|
||||
if str(line).startswith(tuple(["commands", "module.commands", "sopel.module.commands"])):
|
||||
line = str(line).split("commands")[-1]
|
||||
line = "commands" + line
|
||||
detected_lines.append(line)
|
||||
elif str(line).startswith(tuple(["nickname_commands", "module.nickname_commands", "sopel.module.nickname_commands"])):
|
||||
line = str(line).split("nickname_commands")[-1]
|
||||
line = "nickname_commands" + line
|
||||
detected_lines.append(line)
|
||||
elif str(line).startswith(tuple(["rule", "module.rule", "sopel.module.rule"])):
|
||||
line = str(line).split("rule")[-1]
|
||||
line = "rule" + line
|
||||
else:
|
||||
line = None
|
||||
|
||||
if line:
|
||||
detected_lines.append(line)
|
||||
|
||||
if len(detected_lines):
|
||||
|
||||
filelinelist = []
|
||||
currentsuccesslines = 0
|
||||
for detected_line in detected_lines:
|
||||
|
||||
# Commands
|
||||
if str(detected_line).startswith("commands"):
|
||||
comtype = "module"
|
||||
validcoms = eval(str(detected_line).split("commands")[-1])
|
||||
elif str(detected_line).startswith("nickname_commands"):
|
||||
comtype = "nickname"
|
||||
validcoms = eval(str(detected_line).split("nickname_commands")[-1])
|
||||
elif str(detected_line).startswith("rule"):
|
||||
comtype = "rule"
|
||||
validcoms = eval(str(detected_line).split("rule")[-1])
|
||||
|
||||
if isinstance(validcoms, tuple):
|
||||
validcoms = list(validcoms)
|
||||
else:
|
||||
validcoms = [validcoms]
|
||||
for regexcom in ["(.*)", '^\?(.*)']:
|
||||
if regexcom in validcoms:
|
||||
while regexcom in validcoms:
|
||||
validcoms.remove(regexcom)
|
||||
|
||||
if len(validcoms):
|
||||
validcomdict = {"comtype": comtype, "validcoms": validcoms}
|
||||
filelinelist.append(validcomdict)
|
||||
currentsuccesslines += 1
|
||||
|
||||
if currentsuccesslines:
|
||||
bot.memory['SpiceBot_CommandsQuery']['counts'] += 1
|
||||
|
||||
if len(filelinelist):
|
||||
for atlinefound in filelinelist:
|
||||
|
||||
dict_from_file = dict()
|
||||
|
||||
comtype = atlinefound["comtype"]
|
||||
validcoms = atlinefound["validcoms"]
|
||||
|
||||
# default command to filename
|
||||
if "validcoms" not in dict_from_file.keys():
|
||||
dict_from_file["validcoms"] = validcoms
|
||||
|
||||
maincom = dict_from_file["validcoms"][0]
|
||||
if len(dict_from_file["validcoms"]) > 1:
|
||||
comaliases = spicemanip.main(dict_from_file["validcoms"], '2+', 'list')
|
||||
else:
|
||||
comaliases = []
|
||||
|
||||
bot.memory['SpiceBot_CommandsQuery']['commands'][comtype][maincom] = dict_from_file
|
||||
for comalias in comaliases:
|
||||
if comalias not in bot.memory['SpiceBot_CommandsQuery']['commands'][comtype].keys():
|
||||
bot.memory['SpiceBot_CommandsQuery']['commands'][comtype][comalias] = {"aliasfor": maincom}
|
||||
|
||||
for comtype in ['module', 'nickname', 'rule']:
|
||||
botlogs.log('SpiceBot_CommandsQuery', "Found " + str(len(bot.memory['SpiceBot_CommandsQuery']['commands'][comtype].keys())) + " " + comtype + " commands.", True)
|
||||
|
||||
for command in bot.memory['SpiceBot_CommandsQuery']['commands']['rule'].keys():
|
||||
if command.startswith("$nickname"):
|
||||
command = command.split("$nickname")[-1]
|
||||
if command not in bot.memory['SpiceBot_CommandsQuery']['nickrules']:
|
||||
bot.memory['SpiceBot_CommandsQuery']['nickrules'].append(command)
|
||||
|
||||
botevents.trigger(bot, botevents.BOT_COMMANDSQUERY, "SpiceBot_CommandsQuery")
|
||||
|
||||
|
||||
def shutdown(bot):
|
||||
if "SpiceBot_CommandsQuery" in bot.memory:
|
||||
del bot.memory["SpiceBot_CommandsQuery"]
|
||||
|
||||
|
||||
@sopel.module.event(botevents.BOT_LOADED)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_events_complete(bot, trigger):
|
||||
|
||||
for comtype in bot.memory['SpiceBot_CommandsQuery']['commands'].keys():
|
||||
if comtype not in ['module', 'nickname', 'rule']:
|
||||
botlogs.log('SpiceBot_CommandsQuery', "Found " + str(len(bot.memory['SpiceBot_CommandsQuery']['commands'][comtype].keys())) + " " + comtype + " commands.", True)
|
||||
|
||||
|
||||
def commandsquery_register(bot, command_type, validcoms, aliasfor=None):
|
||||
|
||||
if 'SpiceBot_CommandsQuery' not in bot.memory:
|
||||
bot.memory['SpiceBot_CommandsQuery'] = {"counts": 0, "commands": {}, "nickrules": []}
|
||||
|
||||
if not isinstance(validcoms, list):
|
||||
validcoms = [validcoms]
|
||||
|
||||
if command_type not in bot.memory['SpiceBot_CommandsQuery']['commands'].keys():
|
||||
bot.memory['SpiceBot_CommandsQuery']['commands'][command_type] = dict()
|
||||
bot.memory['SpiceBot_CommandsQuery']['counts'] += 1
|
||||
|
||||
dict_from_file = dict()
|
||||
|
||||
# default command to filename
|
||||
if "validcoms" not in dict_from_file.keys():
|
||||
dict_from_file["validcoms"] = validcoms
|
||||
|
||||
if not aliasfor:
|
||||
|
||||
maincom = dict_from_file["validcoms"][0]
|
||||
if len(dict_from_file["validcoms"]) > 1:
|
||||
comaliases = spicemanip.main(dict_from_file["validcoms"], '2+', 'list')
|
||||
else:
|
||||
comaliases = []
|
||||
bot.memory['SpiceBot_CommandsQuery']['commands'][command_type][maincom] = dict_from_file
|
||||
else:
|
||||
comaliases = validcoms
|
||||
|
||||
for comalias in comaliases:
|
||||
if comalias not in bot.memory['SpiceBot_CommandsQuery']['commands'][command_type].keys():
|
||||
bot.memory['SpiceBot_CommandsQuery']['commands'][command_type][comalias] = {"aliasfor": aliasfor}
|
||||
@ -1,79 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel
|
||||
import sopel.module
|
||||
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, similar_list, letters_in_string
|
||||
|
||||
|
||||
import spicemanip
|
||||
|
||||
|
||||
@botevents.check_ready([botevents.BOT_COMMANDSQUERY])
|
||||
@sopel.module.nickname_commands('(.*)')
|
||||
def query_detection_nick(bot, trigger):
|
||||
|
||||
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'nickname_command')
|
||||
|
||||
# command issued, check if valid
|
||||
if not triggercommand or not len(triggercommand):
|
||||
return
|
||||
|
||||
if not triggercommand[0] == "?":
|
||||
return
|
||||
triggercommand = triggercommand[1:]
|
||||
|
||||
if not letters_in_string(triggercommand):
|
||||
return
|
||||
|
||||
commands_list = dict()
|
||||
for com in bot.memory['SpiceBot_CommandsQuery']['commands']['nickname'].keys():
|
||||
if com not in commands_list.keys():
|
||||
commands_list[com] = bot.memory['SpiceBot_CommandsQuery']['commands']['nickname'][com]
|
||||
|
||||
if triggercommand.endswith("+"):
|
||||
|
||||
triggercommand = triggercommand[:-1]
|
||||
if not triggercommand or not len(triggercommand):
|
||||
return
|
||||
|
||||
if triggercommand.lower() not in list(commands_list.keys()):
|
||||
dispmsg = ["Cannot find any alias " + bot.nick + " commands: No valid commands match " + str(triggercommand) + "."]
|
||||
closestmatches = similar_list(bot, triggercommand, list(commands_list.keys()), 10, 'reverse')
|
||||
if len(closestmatches):
|
||||
dispmsg.append("The following " + bot.nick + " commands match " + str(triggercommand) + ": " + spicemanip.main(closestmatches, 'andlist') + ".")
|
||||
bot.notice(dispmsg, trigger.nick)
|
||||
return
|
||||
|
||||
realcom = triggercommand
|
||||
if "aliasfor" in commands_list[triggercommand].keys():
|
||||
realcom = commands_list[triggercommand]["aliasfor"]
|
||||
validcomlist = commands_list[realcom]["validcoms"]
|
||||
bot.notice("The following " + bot.nick + " commands match " + str(triggercommand) + ": " + spicemanip.main(validcomlist, 'andlist') + ".", trigger.nick)
|
||||
return
|
||||
|
||||
if triggercommand.endswith("?"):
|
||||
|
||||
triggercommand = triggercommand[:-1]
|
||||
if not triggercommand or not len(triggercommand):
|
||||
return
|
||||
|
||||
closestmatches = similar_list(bot, triggercommand, list(commands_list.keys()), 10, 'reverse')
|
||||
if not len(closestmatches):
|
||||
bot.notice("Cannot find any similar " + bot.nick + " commands for " + str(triggercommand) + ".", trigger.nick)
|
||||
else:
|
||||
bot.notice("The following " + bot.nick + " commands may match " + str(triggercommand) + ": " + spicemanip.main(closestmatches, 'andlist') + ".", trigger.nick)
|
||||
return
|
||||
|
||||
commandlist = []
|
||||
for command in list(commands_list.keys()):
|
||||
if command.lower().startswith(str(triggercommand).lower()):
|
||||
commandlist.append(command)
|
||||
|
||||
if not len(commandlist):
|
||||
bot.notice("No " + bot.nick + " commands start with " + str(triggercommand) + ".", trigger.nick)
|
||||
else:
|
||||
bot.notice("The following " + bot.nick + " commands start with " + str(triggercommand) + ": " + spicemanip.main(commandlist, 'andlist') + ".", trigger.nick)
|
||||
@ -1,77 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel
|
||||
import sopel.module
|
||||
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, similar_list, letters_in_string
|
||||
|
||||
|
||||
import spicemanip
|
||||
|
||||
|
||||
@botevents.check_ready([botevents.BOT_COMMANDSQUERY])
|
||||
@sopel.module.rule('^\?(.*)')
|
||||
def query_detection(bot, trigger):
|
||||
|
||||
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'query_command')
|
||||
|
||||
# command issued, check if valid
|
||||
if not triggercommand or not len(triggercommand):
|
||||
return
|
||||
|
||||
if not letters_in_string(triggercommand):
|
||||
return
|
||||
|
||||
commands_list = dict()
|
||||
for commandstype in bot.memory['SpiceBot_CommandsQuery']['commands'].keys():
|
||||
if commandstype not in ['rule', 'nickname']:
|
||||
for com in bot.memory['SpiceBot_CommandsQuery']['commands'][commandstype].keys():
|
||||
if com not in commands_list.keys():
|
||||
commands_list[com] = bot.memory['SpiceBot_CommandsQuery']['commands'][commandstype][com]
|
||||
|
||||
if triggercommand[:-1] == "+":
|
||||
|
||||
triggercommand = triggercommand[:-1]
|
||||
if not triggercommand or not len(triggercommand):
|
||||
return
|
||||
|
||||
if triggercommand.lower() not in list(commands_list.keys()):
|
||||
dispmsg = ["Cannot find any alias commands: No valid commands match " + str(triggercommand) + "."]
|
||||
closestmatches = similar_list(bot, triggercommand, list(commands_list.keys()), 10, 'reverse')
|
||||
if len(closestmatches):
|
||||
dispmsg.append("The following commands match " + str(triggercommand) + ": " + spicemanip.main(closestmatches, 'andlist') + ".")
|
||||
bot.notice(dispmsg, trigger.nick)
|
||||
return
|
||||
|
||||
realcom = triggercommand
|
||||
if "aliasfor" in commands_list[triggercommand].keys():
|
||||
realcom = commands_list[triggercommand]["aliasfor"]
|
||||
validcomlist = commands_list[realcom]["validcoms"]
|
||||
bot.notice("The following commands match " + str(triggercommand) + ": " + spicemanip.main(validcomlist, 'andlist') + ".", trigger.nick)
|
||||
return
|
||||
|
||||
if triggercommand[:-1] == "?":
|
||||
|
||||
triggercommand = triggercommand[:-1]
|
||||
if not triggercommand or not len(triggercommand):
|
||||
return
|
||||
|
||||
closestmatches = similar_list(bot, triggercommand, list(commands_list.keys()), 10, 'reverse')
|
||||
if not len(closestmatches):
|
||||
bot.notice("Cannot find any similar commands for " + str(triggercommand) + ".", trigger.nick)
|
||||
else:
|
||||
bot.notice("The following commands may match " + str(triggercommand) + ": " + spicemanip.main(closestmatches, 'andlist') + ".", trigger.nick)
|
||||
return
|
||||
|
||||
commandlist = []
|
||||
for command in list(commands_list.keys()):
|
||||
if command.lower().startswith(str(triggercommand).lower()):
|
||||
commandlist.append(command)
|
||||
|
||||
if not len(commandlist):
|
||||
bot.notice("No commands start with " + str(triggercommand) + ".", trigger.nick)
|
||||
else:
|
||||
bot.notice("The following commands start with " + str(triggercommand) + ": " + spicemanip.main(commandlist, 'andlist') + ".", trigger.nick)
|
||||
@ -1,14 +0,0 @@
|
||||
# coding=utf8
|
||||
"""Sopel Commands Query
|
||||
|
||||
Sopel Commands Query responds to ? to display commands matching patterns
|
||||
"""
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
from .CommandsQuery import *
|
||||
from .QueryCommand import *
|
||||
from .NickQueryCommand import *
|
||||
|
||||
__author__ = 'Sam Zick'
|
||||
__email__ = 'sam@deathbybandaid.net'
|
||||
__version__ = '0.1.1'
|
||||
18
sopel_modules/SpiceBot_Configs/aiml/dog.aiml
Normal file
18
sopel_modules/SpiceBot_Configs/aiml/dog.aiml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>MY DOGS NAME IS *</pattern>
|
||||
<template>
|
||||
That is interesting that you have a dog named <set name="dog"><star/></set>
|
||||
</template>
|
||||
</category>
|
||||
<category>
|
||||
<pattern>WHAT IS MY DOGS NAME</pattern>
|
||||
<template>
|
||||
Your dog's name is <get name="dog"/>.
|
||||
</template>
|
||||
</category>
|
||||
|
||||
|
||||
</aiml>
|
||||
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICKexclamationmark</pattern>
|
||||
<template>triggernick!</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICKquestionmark</pattern>
|
||||
<template>I'm here, triggernick</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>That's my name, don't wear it out!</li>
|
||||
<li>Need something, triggernick?</li>
|
||||
<li>What's going on, triggernick?</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
</aiml>
|
||||
16
sopel_modules/SpiceBot_Configs/aiml/nickname_gender.aiml
Normal file
16
sopel_modules/SpiceBot_Configs/aiml/nickname_gender.aiml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK GENDER</pattern>
|
||||
<template>If societal genders are binary, my gender is <bot name="gender"/></template>
|
||||
</category>
|
||||
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK WHAT IS YOUR GENDER</pattern>
|
||||
<template>If societal genders are binary, my gender is <bot name="gender"/></template>
|
||||
</category>
|
||||
|
||||
|
||||
</aiml>
|
||||
134
sopel_modules/SpiceBot_Configs/aiml/nickname_goodbye.aiml
Normal file
134
sopel_modules/SpiceBot_Configs/aiml/nickname_goodbye.aiml
Normal file
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK BYE</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>bye, triggernick</li>
|
||||
<li>goodbye, triggernick</li>
|
||||
<li>seeya, triggernick</li>
|
||||
<li>cya, triggernick</li>
|
||||
<li>ttyl, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK GOODBYE</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>bye, triggernick</li>
|
||||
<li>goodbye, triggernick</li>
|
||||
<li>seeya, triggernick</li>
|
||||
<li>cya, triggernick</li>
|
||||
<li>ttyl, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK seeya</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>bye, triggernick</li>
|
||||
<li>goodbye, triggernick</li>
|
||||
<li>seeya, triggernick</li>
|
||||
<li>cya, triggernick</li>
|
||||
<li>ttyl, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK cya</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>bye, triggernick</li>
|
||||
<li>goodbye, triggernick</li>
|
||||
<li>seeya, triggernick</li>
|
||||
<li>cya, triggernick</li>
|
||||
<li>ttyl, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK ttyl</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>bye, triggernick</li>
|
||||
<li>goodbye, triggernick</li>
|
||||
<li>seeya, triggernick</li>
|
||||
<li>cya, triggernick</li>
|
||||
<li>ttyl, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BYE BOTNICK</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>bye, triggernick</li>
|
||||
<li>goodbye, triggernick</li>
|
||||
<li>seeya, triggernick</li>
|
||||
<li>cya, triggernick</li>
|
||||
<li>ttyl, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>GOODBYE BOTNICK</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>bye, triggernick</li>
|
||||
<li>goodbye, triggernick</li>
|
||||
<li>seeya, triggernick</li>
|
||||
<li>cya, triggernick</li>
|
||||
<li>ttyl, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>seeya BOTNICK</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>bye, triggernick</li>
|
||||
<li>goodbye, triggernick</li>
|
||||
<li>seeya, triggernick</li>
|
||||
<li>cya, triggernick</li>
|
||||
<li>ttyl, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>cya BOTNICK</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>bye, triggernick</li>
|
||||
<li>goodbye, triggernick</li>
|
||||
<li>seeya, triggernick</li>
|
||||
<li>cya, triggernick</li>
|
||||
<li>ttyl, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>ttyl BOTNICK</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>bye, triggernick</li>
|
||||
<li>goodbye, triggernick</li>
|
||||
<li>seeya, triggernick</li>
|
||||
<li>cya, triggernick</li>
|
||||
<li>ttyl, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
</aiml>
|
||||
70
sopel_modules/SpiceBot_Configs/aiml/nickname_hello.aiml
Normal file
70
sopel_modules/SpiceBot_Configs/aiml/nickname_hello.aiml
Normal file
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK hi</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>hi, triggernick</li>
|
||||
<li>hello, triggernick</li>
|
||||
<li>hey, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK hello</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>hi, triggernick</li>
|
||||
<li>hello, triggernick</li>
|
||||
<li>hey, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK hey</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>hi, triggernick</li>
|
||||
<li>hello, triggernick</li>
|
||||
<li>hey, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>hi BOTNICK</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>hi, triggernick</li>
|
||||
<li>hello, triggernick</li>
|
||||
<li>hey, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>hello BOTNICK</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>hi, triggernick</li>
|
||||
<li>hello, triggernick</li>
|
||||
<li>hey, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>hey BOTNICK</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>hi, triggernick</li>
|
||||
<li>hello, triggernick</li>
|
||||
<li>hey, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
</aiml>
|
||||
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK fuck you</pattern>
|
||||
<template>Watch your mouth, triggernick, or I'll tell your mother!</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK fuck off</pattern>
|
||||
<template>Watch your mouth, triggernick, or I'll tell your mother!</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK screw you</pattern>
|
||||
<template>Watch your mouth, triggernick, or I'll tell your mother!</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>fuck you BOTNICK</pattern>
|
||||
<template>Watch your mouth, triggernick, or I'll tell your mother!</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>fuck off BOTNICK</pattern>
|
||||
<template>Watch your mouth, triggernick, or I'll tell your mother!</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>screw you BOTNICK</pattern>
|
||||
<template>Watch your mouth, triggernick, or I'll tell your mother!</template>
|
||||
</category>
|
||||
|
||||
</aiml>
|
||||
38
sopel_modules/SpiceBot_Configs/aiml/nickname_lazy.aiml
Normal file
38
sopel_modules/SpiceBot_Configs/aiml/nickname_lazy.aiml
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK IS LAZY</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>hi, triggernick</li>
|
||||
<li>hello, triggernick</li>
|
||||
<li>hey, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
|
||||
<category>
|
||||
<pattern>LAZY BOTNICK</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>hi, triggernick</li>
|
||||
<li>hello, triggernick</li>
|
||||
<li>hey, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>DAMNIT BOTNICK</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>hi, triggernick</li>
|
||||
<li>hello, triggernick</li>
|
||||
<li>hey, triggernick</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
</aiml>
|
||||
44
sopel_modules/SpiceBot_Configs/aiml/nickname_love.aiml
Normal file
44
sopel_modules/SpiceBot_Configs/aiml/nickname_love.aiml
Normal file
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK I love you</pattern>
|
||||
<template>triggernick, I love you too.</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK loveya</pattern>
|
||||
<template>triggernick, I love you too.</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK I love you</pattern>
|
||||
<template>triggernick, I love you too.</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK I like you</pattern>
|
||||
<template>triggernick, I like you too.</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>I love you BOTNICK</pattern>
|
||||
<template>triggernick, I love you too.</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>loveya BOTNICK</pattern>
|
||||
<template>triggernick, I love you too.</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>I love BOTNICK</pattern>
|
||||
<template>triggernick, I love you too.</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>I like BOTNICK</pattern>
|
||||
<template>triggernick, I like you too.</template>
|
||||
</category>
|
||||
|
||||
</aiml>
|
||||
9
sopel_modules/SpiceBot_Configs/aiml/nickname_ping.aiml
Normal file
9
sopel_modules/SpiceBot_Configs/aiml/nickname_ping.aiml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK PING</pattern>
|
||||
<template>pong</template>
|
||||
</category>
|
||||
|
||||
</aiml>
|
||||
9
sopel_modules/SpiceBot_Configs/aiml/nickname_praise.aiml
Normal file
9
sopel_modules/SpiceBot_Configs/aiml/nickname_praise.aiml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK IS COOL</pattern>
|
||||
<template>Thanks!</template>
|
||||
</category>
|
||||
|
||||
</aiml>
|
||||
25
sopel_modules/SpiceBot_Configs/aiml/nickname_really.aiml
Normal file
25
sopel_modules/SpiceBot_Configs/aiml/nickname_really.aiml
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK really</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>triggernick, Yes, really.</li>
|
||||
<li>triggernick, Really really</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>really BOTNICK</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>triggernick, Yes, really.</li>
|
||||
<li>triggernick, Really really</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
|
||||
</aiml>
|
||||
34
sopel_modules/SpiceBot_Configs/aiml/nickname_thanks.aiml
Normal file
34
sopel_modules/SpiceBot_Configs/aiml/nickname_thanks.aiml
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>thank you BOTNICK</pattern>
|
||||
<template>triggernick, I like you too.</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK thank you</pattern>
|
||||
<template>triggernick, I like you too.</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>thanks BOTNICK</pattern>
|
||||
<template>triggernick, I like you too.</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK thanks</pattern>
|
||||
<template>triggernick, I like you too.</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>thankya BOTNICK</pattern>
|
||||
<template>triggernick, I like you too.</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK thankya</pattern>
|
||||
<template>triggernick, I like you too.</template>
|
||||
</category>
|
||||
|
||||
</aiml>
|
||||
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK welcome back</pattern>
|
||||
<template>Thanks!</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>welcome back BOTNICK</pattern>
|
||||
<template>Thanks!</template>
|
||||
</category>
|
||||
|
||||
</aiml>
|
||||
9
sopel_modules/SpiceBot_Configs/aiml/nickname_whatis.aiml
Normal file
9
sopel_modules/SpiceBot_Configs/aiml/nickname_whatis.aiml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK what is</pattern>
|
||||
<template>Do you think this is Jeopardy?</template>
|
||||
</category>
|
||||
|
||||
</aiml>
|
||||
29
sopel_modules/SpiceBot_Configs/aiml/nickname_whereis.aiml
Normal file
29
sopel_modules/SpiceBot_Configs/aiml/nickname_whereis.aiml
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<aiml version="1.0">
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK where is waldo</pattern>
|
||||
<template>He is hiding for a reason?</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK where is wally</pattern>
|
||||
<template>He is hiding for a reason?</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK where is carmen sandiego</pattern>
|
||||
<template>
|
||||
<random>
|
||||
<li>Currently she is located at ACME Headquarters</li>
|
||||
<li>Currently she is located at Villains' International League of Evil</li>
|
||||
</random>
|
||||
</template>
|
||||
</category>
|
||||
|
||||
<category>
|
||||
<pattern>BOTNICK where is</pattern>
|
||||
<template>Not sure what you want me to look for.</template>
|
||||
</category>
|
||||
|
||||
</aiml>
|
||||
@ -1,28 +1,26 @@
|
||||
# coding=utf-8
|
||||
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
"""
|
||||
This is the SpiceBot Channels system.
|
||||
"""
|
||||
import sopel
|
||||
|
||||
import spicemanip
|
||||
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
from sopel_modules.SpiceBot.Channels import botchannels
|
||||
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, inlist, channel_privs
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@botevents.check_ready([botevents.BOT_LOADED])
|
||||
@SpiceBot.events.check_ready([SpiceBot.events.BOT_LOADED])
|
||||
@SpiceBot.prerun.prerun('nickname')
|
||||
@sopel.module.nickname_commands('channels', 'channel')
|
||||
def nickname_comand_channels(bot, trigger):
|
||||
|
||||
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'nickname_command')
|
||||
|
||||
if not len(triggerargs):
|
||||
if not len(trigger.sb['args']):
|
||||
commandused = 'list'
|
||||
else:
|
||||
commandused = spicemanip.main(triggerargs, 1).lower()
|
||||
commandused = spicemanip.main(trigger.sb['args'], 1).lower()
|
||||
|
||||
triggerargs = spicemanip.main(triggerargs, '2+', 'list')
|
||||
trigger.sb['args'] = spicemanip.main(trigger.sb['args'], '2+', 'list')
|
||||
|
||||
if commandused == 'list':
|
||||
chanlist = spicemanip.main(bot.channels.keys(), 'andlist')
|
||||
@ -31,14 +29,14 @@ def nickname_comand_channels(bot, trigger):
|
||||
|
||||
elif commandused == 'total':
|
||||
botcount = len(bot.channels.keys())
|
||||
servercount = len(botchannels.SpiceBot_Channels['list'].keys())
|
||||
servercount = len(SpiceBot.channels.dict['list'].keys())
|
||||
bot.osd("I am in " + str(botcount) + " of " + str(servercount) + " channel(s) available on this server.")
|
||||
return
|
||||
|
||||
elif commandused == 'random':
|
||||
channel = spicemanip.main(botchannels.SpiceBot_Channels['list'], 'random')
|
||||
topic = botchannels.SpiceBot_Channels['list'][channel]['topic']
|
||||
msg = ["Random channel for you: {}.".format(botchannels.SpiceBot_Channels['list'][channel]['name'])]
|
||||
channel = spicemanip.main(SpiceBot.channels.dict['list'], 'random')
|
||||
topic = SpiceBot.channels.dict['list'][channel]['topic']
|
||||
msg = ["Random channel for you: {}.".format(SpiceBot.channels.dict['list'][channel]['name'])]
|
||||
if topic and not topic.isspace():
|
||||
msg.append("The topic is: {}".format(topic))
|
||||
else:
|
||||
@ -50,47 +48,47 @@ def nickname_comand_channels(bot, trigger):
|
||||
if not trigger.admin:
|
||||
bot.osd("You do not have permission to update the channel listing.")
|
||||
return
|
||||
botchannels.bot_part_empty(bot)
|
||||
botchannels.channel_list_request(bot)
|
||||
SpiceBot.channels.bot_part_empty(bot)
|
||||
SpiceBot.channels.channel_list_request(bot)
|
||||
bot.osd(["[SpiceBot_Channels]", "I am now updating the channel listing for this server."])
|
||||
while botchannels.channel_lock:
|
||||
while SpiceBot.channels.channel_lock:
|
||||
pass
|
||||
botchannels.join_all_channels(bot)
|
||||
foundchannelcount = len(botchannels.SpiceBot_Channels['list'].keys())
|
||||
SpiceBot.channels.join_all_channels(bot)
|
||||
foundchannelcount = len(SpiceBot.channels.dict['list'].keys())
|
||||
bot.osd("[SpiceBot_Channels]", "Channel listing finished!", str(foundchannelcount) + " channel(s) found.")
|
||||
botchannels.bot_part_empty(bot)
|
||||
SpiceBot.channels.bot_part_empty(bot)
|
||||
return
|
||||
|
||||
elif commandused == 'topic':
|
||||
if not len(triggerargs):
|
||||
if not len(trigger.sb['args']):
|
||||
bot.osd("Channel name input missing.")
|
||||
return
|
||||
channel = spicemanip.main(triggerargs, 1)
|
||||
if not inlist(bot, channel.lower(), botchannels.SpiceBot_Channels['list'].keys()):
|
||||
channel = spicemanip.main(trigger.sb['args'], 1)
|
||||
if not SpiceBot.inlist(channel.lower(), SpiceBot.channels.dict['list'].keys()):
|
||||
bot.osd("Channel name {} not valid.".format(channel))
|
||||
return
|
||||
topic = botchannels.SpiceBot_Channels['list'][channel.lower()]['topic']
|
||||
channel = botchannels.SpiceBot_Channels['list'][channel.lower()]['name']
|
||||
topic = SpiceBot.channels.dict['list'][channel.lower()]['topic']
|
||||
channel = SpiceBot.channels.dict['list'][channel.lower()]['name']
|
||||
bot.osd("Topic for {}: {}".format(channel, topic))
|
||||
return
|
||||
|
||||
if commandused.upper() in ['OP', 'HOP', 'VOICE', 'OWNER', 'ADMIN']:
|
||||
if not len(triggerargs):
|
||||
if not len(trigger.sb['args']):
|
||||
if trigger.is_privmsg:
|
||||
bot.osd("Channel name required.")
|
||||
return
|
||||
else:
|
||||
channel = trigger.sender
|
||||
else:
|
||||
channel = spicemanip.main(triggerargs, 1)
|
||||
if not inlist(bot, channel.lower(), botchannels.SpiceBot_Channels['list'].keys()):
|
||||
channel = spicemanip.main(trigger.sb['args'], 1)
|
||||
if not SpiceBot.inlist(channel.lower(), SpiceBot.channels.dict['list'].keys()):
|
||||
bot.osd("Channel name {} not valid.".format(channel))
|
||||
return
|
||||
if not inlist(bot, channel.lower(), bot.channels.keys()):
|
||||
if not SpiceBot.inlist(channel.lower(), bot.channels.keys()):
|
||||
bot.osd("I need to be in {} to see nick privileges.".format(channel))
|
||||
return
|
||||
|
||||
privlist = channel_privs(bot, channel, commandused.upper())
|
||||
privlist = SpiceBot.channel_privs(bot, channel, commandused.upper())
|
||||
dispmsg = []
|
||||
if not len(privlist):
|
||||
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
|
||||
@ -102,11 +100,11 @@ def nickname_comand_channels(bot, trigger):
|
||||
|
||||
# Users List
|
||||
if commandused == 'users':
|
||||
channel = spicemanip.main(triggerargs, 1)
|
||||
if not inlist(bot, channel.lower(), botchannels.SpiceBot_Channels['list'].keys()):
|
||||
channel = spicemanip.main(trigger.sb['args'], 1)
|
||||
if not SpiceBot.inlist(channel.lower(), SpiceBot.channels.dict['list'].keys()):
|
||||
bot.osd("Channel name {} not valid.".format(channel))
|
||||
return
|
||||
if not inlist(bot, channel.lower(), bot.channels.keys()):
|
||||
if not SpiceBot.inlist(channel.lower(), bot.channels.keys()):
|
||||
bot.osd("I need to be in {} to see user list.".format(channel))
|
||||
return
|
||||
dispmsg = []
|
||||
175
sopel_modules/SpiceBot_Core_Commands/Commands.py
Normal file
175
sopel_modules/SpiceBot_Core_Commands/Commands.py
Normal file
@ -0,0 +1,175 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot Commands system.
|
||||
|
||||
This Class stores commands in an easy to access manner
|
||||
"""
|
||||
import sopel
|
||||
|
||||
import spicemanip
|
||||
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@SpiceBot.events.check_ready([SpiceBot.events.BOT_COMMANDS])
|
||||
@SpiceBot.prerun.prerun('nickname')
|
||||
@sopel.module.nickname_commands('commands', 'command')
|
||||
def nickname_comand_channels(bot, trigger):
|
||||
|
||||
if not len(trigger.sb['args']):
|
||||
commandused = 'list'
|
||||
else:
|
||||
commandused = spicemanip.main(trigger.sb['args'], 1).lower()
|
||||
|
||||
commands_list = []
|
||||
for commandstype in SpiceBot.commands.dict['commands'].keys():
|
||||
if commandstype not in ['rule']:
|
||||
for com in SpiceBot.commands.dict['commands'][commandstype].keys():
|
||||
if com not in commands_list:
|
||||
if commandstype in ['nickname']:
|
||||
commands_list.append(bot.nick + " " + com)
|
||||
else:
|
||||
commands_list.append(com)
|
||||
|
||||
if commandused == 'list':
|
||||
bot.osd(spicemanip.main(commands_list, 'andlist'), trigger.nick, 'NOTICE')
|
||||
return
|
||||
|
||||
elif commandused == 'total':
|
||||
bot.osd("I have " + str(len(commands_list)) + " commands available.")
|
||||
return
|
||||
|
||||
elif commandused == 'random':
|
||||
bot.osd(["Here's a random command for you:", + spicemanip.main(commands_list, 'random')])
|
||||
return
|
||||
|
||||
|
||||
@SpiceBot.events.check_ready([SpiceBot.events.BOT_COMMANDS])
|
||||
@SpiceBot.prerun.prerun('nickname')
|
||||
@sopel.module.nickname_commands('(.*)')
|
||||
def query_detection_nick(bot, trigger):
|
||||
|
||||
# command issued, check if valid
|
||||
if not trigger.sb['com'] or not len(trigger.sb['com']):
|
||||
return
|
||||
|
||||
if not trigger.sb['com'][0] == "?":
|
||||
return
|
||||
trigger.sb['com'] = trigger.sb['com'][1:]
|
||||
|
||||
if not SpiceBot.letters_in_string(trigger.sb['com']):
|
||||
return
|
||||
|
||||
commands_list = dict()
|
||||
for com in SpiceBot.commands.dict['commands']['nickname'].keys():
|
||||
if com not in commands_list.keys():
|
||||
commands_list[com] = SpiceBot.commands.dict['commands']['nickname'][com]
|
||||
|
||||
if trigger.sb['com'].endswith("+"):
|
||||
|
||||
trigger.sb['com'] = trigger.sb['com'][:-1]
|
||||
if not trigger.sb['com'] or not len(trigger.sb['com']):
|
||||
return
|
||||
|
||||
if trigger.sb['com'].lower() not in list(commands_list.keys()):
|
||||
dispmsg = ["Cannot find any alias " + bot.nick + " commands: No valid commands match " + str(trigger.sb['com']) + "."]
|
||||
closestmatches = SpiceBot.similar_list(trigger.sb['com'], list(commands_list.keys()), 10, 'reverse')
|
||||
if len(closestmatches):
|
||||
dispmsg.append("The following " + bot.nick + " commands match " + str(trigger.sb['com']) + ": " + spicemanip.main(closestmatches, 'andlist') + ".")
|
||||
bot.osd(dispmsg, trigger.nick, 'notice')
|
||||
return
|
||||
|
||||
realcom = trigger.sb['com']
|
||||
if "aliasfor" in commands_list[trigger.sb['com']].keys():
|
||||
realcom = commands_list[trigger.sb['com']]["aliasfor"]
|
||||
validcomlist = commands_list[realcom]["validcoms"]
|
||||
bot.osd("The following " + bot.nick + " commands match " + str(trigger.sb['com']) + ": " + spicemanip.main(validcomlist, 'andlist') + ".", trigger.nick, 'notice')
|
||||
return
|
||||
|
||||
if trigger.sb['com'].endswith("?"):
|
||||
|
||||
trigger.sb['com'] = trigger.sb['com'][:-1]
|
||||
if not trigger.sb['com'] or not len(trigger.sb['com']):
|
||||
return
|
||||
|
||||
closestmatches = SpiceBot.similar_list(trigger.sb['com'], list(commands_list.keys()), 10, 'reverse')
|
||||
if not len(closestmatches):
|
||||
bot.osd("Cannot find any similar " + bot.nick + " commands for " + str(trigger.sb['com']) + ".", trigger.nick, 'notice')
|
||||
else:
|
||||
bot.osd("The following " + bot.nick + " commands may match " + str(trigger.sb['com']) + ": " + spicemanip.main(closestmatches, 'andlist') + ".", trigger.nick, 'notice')
|
||||
return
|
||||
|
||||
commandlist = []
|
||||
for command in list(commands_list.keys()):
|
||||
if command.lower().startswith(str(trigger.sb['com']).lower()):
|
||||
commandlist.append(command)
|
||||
|
||||
if not len(commandlist):
|
||||
bot.osd("No " + bot.nick + " commands start with " + str(trigger.sb['com']) + ".", trigger.nick, 'notice')
|
||||
else:
|
||||
bot.osd("The following " + bot.nick + " commands start with " + str(trigger.sb['com']) + ": " + spicemanip.main(commandlist, 'andlist') + ".", trigger.nick, 'notice')
|
||||
|
||||
|
||||
@SpiceBot.events.check_ready([SpiceBot.events.BOT_COMMANDS])
|
||||
@SpiceBot.prerun.prerun('query')
|
||||
@sopel.module.rule('^\?(.*)')
|
||||
def query_detection(bot, trigger):
|
||||
|
||||
# command issued, check if valid
|
||||
if not trigger.sb['com'] or not len(trigger.sb['com']):
|
||||
return
|
||||
|
||||
if not SpiceBot.letters_in_string(trigger.sb['com']):
|
||||
return
|
||||
|
||||
commands_list = dict()
|
||||
for commandstype in SpiceBot.commands.dict['commands'].keys():
|
||||
if commandstype not in ['rule', 'nickname']:
|
||||
for com in SpiceBot.commands.dict['commands'][commandstype].keys():
|
||||
if com not in commands_list.keys():
|
||||
commands_list[com] = SpiceBot.commands.dict['commands'][commandstype][com]
|
||||
|
||||
if trigger.sb['com'][:-1] == "+":
|
||||
|
||||
trigger.sb['com'] = trigger.sb['com'][:-1]
|
||||
if not trigger.sb['com'] or not len(trigger.sb['com']):
|
||||
return
|
||||
|
||||
if trigger.sb['com'].lower() not in list(commands_list.keys()):
|
||||
dispmsg = ["Cannot find any alias commands: No valid commands match " + str(trigger.sb['com']) + "."]
|
||||
closestmatches = SpiceBot.similar_list(trigger.sb['com'], list(commands_list.keys()), 10, 'reverse')
|
||||
if len(closestmatches):
|
||||
dispmsg.append("The following commands match " + str(trigger.sb['com']) + ": " + spicemanip.main(closestmatches, 'andlist') + ".")
|
||||
bot.osd(dispmsg, trigger.nick, 'notice')
|
||||
return
|
||||
|
||||
realcom = trigger.sb['com']
|
||||
if "aliasfor" in commands_list[trigger.sb['com']].keys():
|
||||
realcom = commands_list[trigger.sb['com']]["aliasfor"]
|
||||
validcomlist = commands_list[realcom]["validcoms"]
|
||||
bot.osd("The following commands match " + str(trigger.sb['com']) + ": " + spicemanip.main(validcomlist, 'andlist') + ".", trigger.nick, 'notice')
|
||||
return
|
||||
|
||||
if trigger.sb['com'][:-1] == "?":
|
||||
|
||||
trigger.sb['com'] = trigger.sb['com'][:-1]
|
||||
if not trigger.sb['com'] or not len(trigger.sb['com']):
|
||||
return
|
||||
|
||||
closestmatches = SpiceBot.similar_list(trigger.sb['com'], list(commands_list.keys()), 10, 'reverse')
|
||||
if not len(closestmatches):
|
||||
bot.osd("Cannot find any similar commands for " + str(trigger.sb['com']) + ".", trigger.nick, 'notice')
|
||||
else:
|
||||
bot.osd("The following commands may match " + str(trigger.sb['com']) + ": " + spicemanip.main(closestmatches, 'andlist') + ".", trigger.nick, 'notice')
|
||||
return
|
||||
|
||||
commandlist = []
|
||||
for command in list(commands_list.keys()):
|
||||
if command.lower().startswith(str(trigger.sb['com']).lower()):
|
||||
commandlist.append(command)
|
||||
|
||||
if not len(commandlist):
|
||||
bot.osd("No commands start with " + str(trigger.sb['com']) + ".", trigger.nick, 'notice')
|
||||
else:
|
||||
bot.osd("The following commands start with " + str(trigger.sb['com']) + ": " + spicemanip.main(commandlist, 'andlist') + ".", trigger.nick, 'notice')
|
||||
15
sopel_modules/SpiceBot_Core_Commands/Database.py
Normal file
15
sopel_modules/SpiceBot_Core_Commands/Database.py
Normal file
@ -0,0 +1,15 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot Database
|
||||
"""
|
||||
|
||||
# sopel imports
|
||||
import sopel.module
|
||||
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@sopel.module.nickname_commands('database')
|
||||
def bot_command_database(bot, trigger):
|
||||
bot.osd("Database is " + SpiceBot.config.db_type)
|
||||
16
sopel_modules/SpiceBot_Core_Commands/Docs.py
Normal file
16
sopel_modules/SpiceBot_Core_Commands/Docs.py
Normal file
@ -0,0 +1,16 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@sopel.module.nickname_commands('help', 'docs', 'wiki')
|
||||
def bot_command_owners(bot, trigger):
|
||||
bot.osd(["IRC Modules Repository",
|
||||
str(SpiceBot.github_dict["url_main"] +
|
||||
SpiceBot.github_dict["repo_owner"] + "/" +
|
||||
SpiceBot.github_dict["repo_name"] +
|
||||
SpiceBot.github_dict["url_path_wiki"])])
|
||||
49
sopel_modules/SpiceBot_Core_Commands/Logs.py
Normal file
49
sopel_modules/SpiceBot_Core_Commands/Logs.py
Normal file
@ -0,0 +1,49 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot Logs System
|
||||
"""
|
||||
|
||||
# sopel imports
|
||||
import sopel.module
|
||||
|
||||
import spicemanip
|
||||
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@SpiceBot.events.check_ready([SpiceBot.events.BOT_LOGS])
|
||||
@SpiceBot.prerun.prerun('nickname')
|
||||
@sopel.module.nickname_commands('logs', 'debug')
|
||||
def bot_command_logs(bot, trigger):
|
||||
|
||||
if not SpiceBot.command_permissions_check(bot, trigger, ['admins', 'owner', 'OP', 'ADMIN', 'OWNER']):
|
||||
bot.osd("I was unable to process this Bot Nick command due to privilege issues.")
|
||||
return
|
||||
|
||||
logtype = spicemanip.main(trigger.sb['args'], 1) or None
|
||||
if not logtype:
|
||||
bot.osd("Current valid log(s) include: " + spicemanip.main(SpiceBot.logs.dict["list"].keys(), 'andlist'), trigger.sender, 'action')
|
||||
return
|
||||
|
||||
if not SpiceBot.inlist(logtype, SpiceBot.logs.dict["list"].keys()):
|
||||
closestmatches = SpiceBot.similar_list(logtype, SpiceBot.logs.dict["list"].keys(), 10, 'reverse')
|
||||
if not len(closestmatches):
|
||||
bot.osd("No valid logs match " + str(logtype) + ".", trigger.nick, 'notice')
|
||||
else:
|
||||
bot.osd("The following commands may match " + str(logtype) + ": " + spicemanip.main(closestmatches, 'andlist') + ".", trigger.nick, 'notice')
|
||||
|
||||
return
|
||||
|
||||
logtype = SpiceBot.inlist_match(logtype, SpiceBot.logs.dict["list"].keys())
|
||||
|
||||
logindex = SpiceBot.logs.get_logs(logtype)
|
||||
|
||||
if not len(logindex):
|
||||
bot.osd("No logs found for " + str(logtype) + ".")
|
||||
return
|
||||
|
||||
bot.osd("Is Examining " + str(logtype) + " log(s).")
|
||||
for line in logindex:
|
||||
bot.osd(" " + str(line))
|
||||
bot.osd(str(logtype) + " log(s) Complete.")
|
||||
@ -6,20 +6,22 @@ import sopel.module
|
||||
|
||||
import spicemanip
|
||||
|
||||
from sopel_modules.SpiceBot.Channels import botchannels
|
||||
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, command_permissions_check, inlist
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@SpiceBot.prerun.prerun('nickname')
|
||||
@sopel.module.nickname_commands('action')
|
||||
def bot_command_action(bot, trigger):
|
||||
bot_command_process(bot, trigger)
|
||||
|
||||
|
||||
@SpiceBot.prerun.prerun('nickname')
|
||||
@sopel.module.nickname_commands('notice')
|
||||
def bot_command_notice(bot, trigger):
|
||||
bot_command_process(bot, trigger)
|
||||
|
||||
|
||||
@SpiceBot.prerun.prerun('nickname')
|
||||
@sopel.module.nickname_commands('privmsg', 'say', 'msg')
|
||||
def bot_command_privmsg(bot, trigger):
|
||||
bot_command_process(bot, trigger)
|
||||
@ -27,27 +29,25 @@ def bot_command_privmsg(bot, trigger):
|
||||
|
||||
def bot_command_process(bot, trigger):
|
||||
|
||||
if not command_permissions_check(bot, trigger, ['admins', 'owner']):
|
||||
bot.say("I was unable to process this Bot Nick command due to privilege issues.")
|
||||
if not SpiceBot.command_permissions_check(bot, trigger, ['admins', 'owner']):
|
||||
bot.osd("I was unable to process this Bot Nick command due to privilege issues.")
|
||||
return
|
||||
|
||||
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'nickname_command')
|
||||
if trigger.sb['com'] in ['say', 'msg']:
|
||||
trigger.sb['com'] = 'privmsg'
|
||||
|
||||
if triggercommand in ['say', 'msg']:
|
||||
triggercommand = 'privmsg'
|
||||
|
||||
if not len(triggerargs):
|
||||
bot.say("You must specify a channel or nick.")
|
||||
if not len(trigger.sb['args']):
|
||||
bot.osd("You must specify a channel or nick.")
|
||||
return
|
||||
|
||||
target = spicemanip.main(triggerargs, 1)
|
||||
target = spicemanip.main(trigger.sb['args'], 1)
|
||||
if (target not in ['allchans', 'allnicks']
|
||||
and not inlist(bot, target.lower(), botchannels.SpiceBot_Channels['list'].keys())
|
||||
and not inlist(bot, target.lower(), bot.users)):
|
||||
and not SpiceBot.inlist(target.lower(), SpiceBot.channels.dict['list'].keys())
|
||||
and not SpiceBot.inlist(target.lower(), bot.users)):
|
||||
bot.osd("Channel/nick name {} not valid.".format(target))
|
||||
return
|
||||
|
||||
triggerargs = spicemanip.main(triggerargs, '2+', 'list')
|
||||
trigger.sb['args'] = spicemanip.main(trigger.sb['args'], '2+', 'list')
|
||||
|
||||
if target == 'allchans':
|
||||
targetsendlist = bot.channels.keys()
|
||||
@ -56,9 +56,9 @@ def bot_command_process(bot, trigger):
|
||||
else:
|
||||
targetsendlist = [target]
|
||||
|
||||
botmessage = spicemanip.main(triggerargs, 0)
|
||||
botmessage = spicemanip.main(trigger.sb['args'], 0)
|
||||
if not botmessage:
|
||||
bot.say("You must specify a message to send.")
|
||||
bot.osd("You must specify a message to send.")
|
||||
return
|
||||
|
||||
bot.osd(botmessage, targetsendlist, triggercommand.upper())
|
||||
bot.osd(botmessage, targetsendlist, trigger.sb['com'].upper())
|
||||
55
sopel_modules/SpiceBot_Core_Commands/Runtime_Controls.py
Normal file
55
sopel_modules/SpiceBot_Core_Commands/Runtime_Controls.py
Normal file
@ -0,0 +1,55 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
import spicemanip
|
||||
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@SpiceBot.prerun.prerun('nickname')
|
||||
@sopel.module.nickname_commands('update')
|
||||
def nickname_comand_update(bot, trigger):
|
||||
|
||||
if not SpiceBot.command_permissions_check(bot, trigger, ['admins', 'owner', 'OP', 'ADMIN', 'OWNER']):
|
||||
bot.osd("I was unable to process this Bot Nick command due to privilege issues.")
|
||||
return
|
||||
|
||||
if not len(trigger.sb['args']):
|
||||
commandused = 'nodeps'
|
||||
else:
|
||||
commandused = spicemanip.main(trigger.sb['args'], 1).lower()
|
||||
|
||||
if commandused not in ['deps', 'nodeps']:
|
||||
bot.osd("Please specify deps or nodeps")
|
||||
return
|
||||
|
||||
trigger.sb['args'] = spicemanip.main(trigger.sb['args'], '2+', 'list')
|
||||
|
||||
quitmessage = "Received command from " + trigger.nick + " to update from Github and restart"
|
||||
SpiceBot.logs.log('SpiceBot_Update', quitmessage)
|
||||
bot.osd(quitmessage, bot.channels.keys())
|
||||
|
||||
if commandused == 'nodeps':
|
||||
SpiceBot.spicebot_update(False)
|
||||
if commandused == 'deps':
|
||||
SpiceBot.spicebot_update(True)
|
||||
|
||||
# service_manip(bot.nick, 'restart', 'SpiceBot_Update')
|
||||
SpiceBot.spicebot_reload(bot, 'SpiceBot_Update', quitmessage)
|
||||
|
||||
|
||||
@sopel.module.nickname_commands('restart')
|
||||
def nickname_comand_restart(bot, trigger):
|
||||
|
||||
if not trigger.admin:
|
||||
bot.osd("You are not authorized to perform this function.")
|
||||
|
||||
quitmessage = "Received command from " + trigger.nick + " to restart. Be Back Soon!"
|
||||
SpiceBot.logs.log('SpiceBot_Restart', quitmessage)
|
||||
bot.osd(quitmessage, bot.channels.keys())
|
||||
|
||||
# service_manip(bot.nick, 'restart', 'SpiceBot_Restart')
|
||||
SpiceBot.spicebot_reload(bot, 'SpiceBot_Restart', quitmessage)
|
||||
15
sopel_modules/SpiceBot_Core_Commands/Uptime.py
Normal file
15
sopel_modules/SpiceBot_Core_Commands/Uptime.py
Normal file
@ -0,0 +1,15 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
import time
|
||||
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@sopel.module.nickname_commands('uptime')
|
||||
def bot_command_srewyou(bot, trigger):
|
||||
timesince = str(SpiceBot.humanized_time(time.time() - SpiceBot.events.BOT_UPTIME)) + " ago."
|
||||
bot.osd("I have been running since " + timesince)
|
||||
20
sopel_modules/SpiceBot_Core_Commands/__init__.py
Normal file
20
sopel_modules/SpiceBot_Core_Commands/__init__.py
Normal file
@ -0,0 +1,20 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
These are the core SpiceBot Classes
|
||||
|
||||
This module contains references only for other modules to utilize.
|
||||
"""
|
||||
|
||||
from .Commands import *
|
||||
from .Channels import *
|
||||
from .Database import *
|
||||
from .Uptime import *
|
||||
from .Logs import *
|
||||
from .Runtime_Controls import *
|
||||
from .Messaging import *
|
||||
from .Docs import *
|
||||
|
||||
__author__ = 'Sam Zick'
|
||||
__email__ = 'sam@deathbybandaid.net'
|
||||
__version__ = '0.1.1'
|
||||
17
sopel_modules/SpiceBot_Core_Processing/AI.py
Normal file
17
sopel_modules/SpiceBot_Core_Processing/AI.py
Normal file
@ -0,0 +1,17 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot AI system.
|
||||
"""
|
||||
import sopel
|
||||
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.BOT_READY)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_events_complete_ai(bot, trigger):
|
||||
|
||||
SpiceBot.logs.log('SpiceBot_Commands', "Found " + str(SpiceBot.botai.dict['patterncounts']) + " AI pattern Matches.", True)
|
||||
|
||||
SpiceBot.events.trigger(bot, SpiceBot.events.BOT_AI, "SpiceBot_AI")
|
||||
97
sopel_modules/SpiceBot_Core_Processing/Channels.py
Normal file
97
sopel_modules/SpiceBot_Core_Processing/Channels.py
Normal file
@ -0,0 +1,97 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot Channels system.
|
||||
"""
|
||||
import sopel
|
||||
|
||||
import time
|
||||
|
||||
import spicemanip
|
||||
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.RPL_WELCOME)
|
||||
@sopel.module.rule('.*')
|
||||
def unkickable_bot(bot, trigger):
|
||||
if SpiceBot.config.SpiceBot_Channels.operadmin:
|
||||
bot.write(('SAMODE', bot.nick, '+q'))
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.RPL_WELCOME)
|
||||
@sopel.module.rule('.*')
|
||||
def request_channels_list_initial(bot, trigger):
|
||||
|
||||
SpiceBot.channels.bot_part_empty(bot)
|
||||
|
||||
SpiceBot.logs.log('SpiceBot_Channels', "Sending Request for all server channels")
|
||||
SpiceBot.channels.channel_list_request(bot)
|
||||
|
||||
starttime = time.time()
|
||||
|
||||
# wait 60 seconds for initial population of information
|
||||
while not SpiceBot.channels.dict['InitialProcess']:
|
||||
if time.time() - starttime >= 60:
|
||||
SpiceBot.logs.log('SpiceBot_Channels', "Initial Channel list populating Timed Out")
|
||||
SpiceBot.channels.dict['InitialProcess'] = True
|
||||
else:
|
||||
pass
|
||||
|
||||
foundchannelcount = len(SpiceBot.channels.dict['list'].keys())
|
||||
SpiceBot.logs.log('SpiceBot_Channels', "Channel listing finished! " + str(foundchannelcount) + " channel(s) found.")
|
||||
|
||||
SpiceBot.channels.join_all_channels(bot)
|
||||
SpiceBot.channels.chanadmin_all_channels(bot)
|
||||
|
||||
if "*" in SpiceBot.channels.dict['list'].keys():
|
||||
del SpiceBot.channels.dict['list']["*"]
|
||||
|
||||
SpiceBot.channels.bot_part_empty(bot)
|
||||
SpiceBot.events.trigger(bot, SpiceBot.events.BOT_CHANNELS, "SpiceBot_Channels")
|
||||
|
||||
|
||||
@sopel.module.event('321')
|
||||
@sopel.module.rule('.*')
|
||||
def watch_chanlist_start(bot, trigger):
|
||||
SpiceBot.channels.channel_list_recieve_start()
|
||||
|
||||
|
||||
@sopel.module.event('322')
|
||||
@sopel.module.rule('.*')
|
||||
def watch_chanlist_populate(bot, trigger):
|
||||
SpiceBot.channels.channel_list_recieve_input(trigger)
|
||||
|
||||
|
||||
@sopel.module.event('323')
|
||||
@sopel.module.rule('.*')
|
||||
def watch_chanlist_complete(bot, trigger):
|
||||
SpiceBot.channels.channel_list_recieve_finish()
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.BOT_CHANNELS)
|
||||
@sopel.module.rule('.*')
|
||||
def trigger_channel_list_recurring(bot, trigger):
|
||||
while True:
|
||||
time.sleep(1800)
|
||||
SpiceBot.channels.bot_part_empty(bot)
|
||||
|
||||
oldlist = list(SpiceBot.channels.dict['list'].keys())
|
||||
SpiceBot.channels.channel_list_request(bot)
|
||||
|
||||
while SpiceBot.channels.channel_lock:
|
||||
pass
|
||||
|
||||
newlist = [item.lower() for item in oldlist if item.lower() not in list(SpiceBot.channels.dict['list'].keys())]
|
||||
if "*" in newlist:
|
||||
newlist.remove("*")
|
||||
if len(newlist) and SpiceBot.config.SpiceBot_Channels.announcenew:
|
||||
bot.osd(["The Following channel(s) are new:", spicemanip.main(newlist, 'andlist')], bot.channels.keys())
|
||||
|
||||
SpiceBot.channels.join_all_channels(bot)
|
||||
|
||||
SpiceBot.channels.chanadmin_all_channels(bot)
|
||||
|
||||
if "*" in SpiceBot.channels.dict['list'].keys():
|
||||
del SpiceBot.channels.dict['list']["*"]
|
||||
SpiceBot.channels.bot_part_empty(bot)
|
||||
54
sopel_modules/SpiceBot_Core_Processing/Events.py
Normal file
54
sopel_modules/SpiceBot_Core_Processing/Events.py
Normal file
@ -0,0 +1,54 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot Events system.
|
||||
"""
|
||||
import sopel
|
||||
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.BOT_WELCOME, SpiceBot.events.BOT_READY, SpiceBot.events.BOT_CONNECTED, SpiceBot.events.BOT_LOADED)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_events_complete(bot, trigger):
|
||||
"""This is here simply to log to stderr that this was recieved."""
|
||||
SpiceBot.logs.log('SpiceBot_Events', trigger.args[1], True)
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.RPL_WELCOME)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_events_connected(bot, trigger):
|
||||
|
||||
# Handling for connection count
|
||||
SpiceBot.events.dict["RPL_WELCOME_Count"] += 1
|
||||
if SpiceBot.events.dict["RPL_WELCOME_Count"] > 1:
|
||||
SpiceBot.events.trigger(bot, SpiceBot.events.BOT_RECONNECTED, "Bot ReConnected to IRC")
|
||||
else:
|
||||
SpiceBot.events.trigger(bot, SpiceBot.events.BOT_WELCOME, "Welcome to the SpiceBot Events System")
|
||||
|
||||
"""For items tossed in a queue, this will trigger them accordingly"""
|
||||
while True:
|
||||
if len(SpiceBot.events.dict["trigger_queue"]):
|
||||
pretriggerdict = SpiceBot.events.dict["trigger_queue"][0]
|
||||
SpiceBot.events.dispatch(bot, pretriggerdict)
|
||||
del SpiceBot.events.dict["trigger_queue"][0]
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.BOT_WELCOME)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_events_start(bot, trigger):
|
||||
"""This stage is redundant, but shows the system is working."""
|
||||
SpiceBot.events.trigger(bot, SpiceBot.events.BOT_READY, "Ready To Process module setup procedures")
|
||||
|
||||
"""Here, we wait until we are in at least one channel"""
|
||||
while not len(bot.channels.keys()) > 0:
|
||||
pass
|
||||
SpiceBot.events.trigger(bot, SpiceBot.events.BOT_CONNECTED, "Bot Connected to IRC")
|
||||
|
||||
|
||||
@SpiceBot.events.startup_check_ready()
|
||||
@sopel.module.event(SpiceBot.events.BOT_READY)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_events_startup_complete(bot, trigger):
|
||||
"""All events registered as required for startup have completed"""
|
||||
SpiceBot.events.trigger(bot, SpiceBot.events.BOT_LOADED, "All registered modules setup procedures have completed")
|
||||
28
sopel_modules/SpiceBot_Core_Processing/Kick.py
Normal file
28
sopel_modules/SpiceBot_Core_Processing/Kick.py
Normal file
@ -0,0 +1,28 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot OSD system.
|
||||
"""
|
||||
import sopel
|
||||
|
||||
|
||||
@sopel.module.event('005')
|
||||
@sopel.module.rule('.*')
|
||||
def parse_event_005(bot, trigger):
|
||||
if trigger.args[-1] != 'are supported by this server':
|
||||
return
|
||||
parameters = trigger.args[1:-1]
|
||||
for param in parameters:
|
||||
if '=' in param:
|
||||
if param.startswith("TARGMAX"):
|
||||
param = str(param).split('=')[1]
|
||||
settings = str(param).split(',')
|
||||
for setting in settings:
|
||||
settingname = str(setting).split(':')[0]
|
||||
if settingname.upper() in ['KICK']:
|
||||
try:
|
||||
value = str(setting).split(':')[1] or None
|
||||
except IndexError:
|
||||
value = None
|
||||
if value:
|
||||
bot.config.SpiceBot_Kick.kick = int(value)
|
||||
27
sopel_modules/SpiceBot_Core_Processing/Logs.py
Normal file
27
sopel_modules/SpiceBot_Core_Processing/Logs.py
Normal file
@ -0,0 +1,27 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot Logs system.
|
||||
"""
|
||||
import sopel
|
||||
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.RPL_WELCOME)
|
||||
@sopel.module.rule('.*')
|
||||
def join_log_channel(bot, trigger):
|
||||
|
||||
if SpiceBot.config.logging_channel:
|
||||
channel = bot.config.core.logging_channel
|
||||
if channel not in bot.channels.keys():
|
||||
bot.write(('JOIN', bot.nick, channel))
|
||||
if channel not in bot.channels.keys() and bot.config.SpiceBot_Channels.operadmin:
|
||||
bot.write(('SAJOIN', bot.nick, channel))
|
||||
|
||||
while True:
|
||||
if len(SpiceBot.logs.dict["queue"]):
|
||||
bot.osd(str(SpiceBot.logs.dict["queue"][0]), channel)
|
||||
del SpiceBot.logs.dict["queue"][0]
|
||||
else:
|
||||
SpiceBot.logs.dict["queue"] = []
|
||||
19
sopel_modules/SpiceBot_Core_Processing/Modules.py
Normal file
19
sopel_modules/SpiceBot_Core_Processing/Modules.py
Normal file
@ -0,0 +1,19 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot Modules system.
|
||||
"""
|
||||
import sopel
|
||||
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.BOT_READY)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_events_complete_modules(bot, trigger):
|
||||
|
||||
for comtype in SpiceBot.commands.dict['commands'].keys():
|
||||
if comtype not in ['module', 'nickname', 'rule']:
|
||||
SpiceBot.logs.log('SpiceBot_Commands', "Found " + str(len(SpiceBot.commands.dict['commands'][comtype].keys())) + " " + comtype + " commands.", True)
|
||||
|
||||
SpiceBot.events.trigger(bot, SpiceBot.events.BOT_COMMANDS, "SpiceBot_Commands")
|
||||
93
sopel_modules/SpiceBot_Core_Processing/StartupMonologue.py
Normal file
93
sopel_modules/SpiceBot_Core_Processing/StartupMonologue.py
Normal file
@ -0,0 +1,93 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot StartupMonologue system.
|
||||
"""
|
||||
import sopel
|
||||
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
import time
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.BOT_CONNECTED)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_startup_monologue_start(bot, trigger):
|
||||
# Startup
|
||||
SpiceBot.logs.log('SpiceBot_StartupMonologue', bot.nick + " is now starting. Please wait while I load my configuration")
|
||||
bot.osd(" is now starting. Please wait while I load my configuration.", bot.channels.keys(), 'ACTION')
|
||||
SpiceBot.events.trigger(bot, SpiceBot.events.BOT_STARTUPMONOLOGUE_CONNECTED, "SpiceBot_StartupMonologue")
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.BOT_CHANNELS)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_startup_monologue_channels(bot, trigger):
|
||||
botcount = len(bot.channels.keys())
|
||||
servercount = len(SpiceBot.channels.dict['list'].keys())
|
||||
displayval = "I am in " + str(botcount) + " of " + str(servercount) + " channel(s) available on this server."
|
||||
SpiceBot.startupmonologue.dict["channels"] = displayval
|
||||
SpiceBot.logs.log('SpiceBot_StartupMonologue', displayval)
|
||||
SpiceBot.events.trigger(bot, SpiceBot.events.BOT_STARTUPMONOLOGUE_CHANNELS, "SpiceBot_StartupMonologue")
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.BOT_COMMANDS)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_startup_monologue_commands(bot, trigger):
|
||||
availablecomsnum, availablecomsfiles = 0, 0
|
||||
for commandstype in SpiceBot.commands.dict['commands'].keys():
|
||||
availablecomsnum += len(SpiceBot.commands.dict['commands'][commandstype].keys())
|
||||
availablecomsfiles += SpiceBot.commands.dict['counts']
|
||||
displayval = "There are " + str(availablecomsnum) + " commands available in " + str(availablecomsfiles) + " files."
|
||||
SpiceBot.startupmonologue.dict["commands"] = displayval
|
||||
SpiceBot.logs.log('SpiceBot_StartupMonologue', displayval)
|
||||
SpiceBot.events.trigger(bot, SpiceBot.events.BOT_STARTUPMONOLOGUE_COMMANDS, "SpiceBot_StartupMonologue")
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.BOT_AI)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_startup_monologue_ai(bot, trigger):
|
||||
availablecomsnum = SpiceBot.botai.dict['patterncounts']
|
||||
availablecomsfiles = SpiceBot.botai.dict['filecounts']
|
||||
displayval = "There are " + str(availablecomsnum) + " AI pattern matches available in " + str(availablecomsfiles) + " files."
|
||||
SpiceBot.startupmonologue.dict["ai"] = displayval
|
||||
SpiceBot.logs.log('SpiceBot_StartupMonologue', displayval)
|
||||
SpiceBot.events.trigger(bot, SpiceBot.events.BOT_STARTUPMONOLOGUE_AI, "SpiceBot_StartupMonologue")
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.BOT_LOADED)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_startup_monologue_display(bot, trigger):
|
||||
dispmsg = [" startup complete"]
|
||||
for messagekey in SpiceBot.startupmonologue.dict.keys():
|
||||
dispmsg.append(SpiceBot.startupmonologue.dict[messagekey])
|
||||
if SpiceBot.events.dict["RPL_WELCOME_Count"] == 1:
|
||||
timesince = SpiceBot.humanized_time(time.time() - SpiceBot.events.BOT_UPTIME)
|
||||
if timesince == "just now":
|
||||
timesince = "1 second"
|
||||
dispmsg.append("Startup took " + timesince)
|
||||
# Announce to chan, then handle some closing stuff
|
||||
SpiceBot.logs.log('SpiceBot_StartupMonologue', bot.nick + " startup complete")
|
||||
bot.osd(dispmsg, bot.channels.keys(), 'ACTION')
|
||||
SpiceBot.events.trigger(bot, SpiceBot.events.BOT_STARTUPMONOLOGUE, "SpiceBot_StartupMonologue")
|
||||
SpiceBot.logs.log('SpiceBot_StartupMonologue', "Startup Monologue has been issued to all channels.", True)
|
||||
|
||||
|
||||
@sopel.module.event(SpiceBot.events.BOT_STARTUPMONOLOGUE)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_startup_monologue_errors(bot, trigger):
|
||||
|
||||
debuglines = SpiceBot.logs.stdio_logs_fetch()
|
||||
|
||||
searchphrasefound = []
|
||||
for line in debuglines:
|
||||
if str(line).endswith("failed to load") and not str(line).startswith("0"):
|
||||
searchphrasefound.append(line)
|
||||
|
||||
if len(searchphrasefound):
|
||||
for foundphase in searchphrasefound:
|
||||
SpiceBot.logs.log('SpiceBot_Logs', str(foundphase))
|
||||
searchphrasefound.insert(0, "Notice to Bot Admins: ")
|
||||
searchphrasefound.append("Run the debug command for more information.")
|
||||
bot.osd(searchphrasefound, bot.channels.keys())
|
||||
else:
|
||||
SpiceBot.logs.log('SpiceBot_Logs', "No issues found at bot startup!", True)
|
||||
21
sopel_modules/SpiceBot_Core_Processing/__init__.py
Normal file
21
sopel_modules/SpiceBot_Core_Processing/__init__.py
Normal file
@ -0,0 +1,21 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
These are the core SpiceBot Classes
|
||||
|
||||
This module contains references only for other modules to utilize.
|
||||
"""
|
||||
|
||||
from .Channels import *
|
||||
from .Events import *
|
||||
from .Modules import *
|
||||
from .AI import *
|
||||
from .osd import *
|
||||
from .StartupMonologue import *
|
||||
from .Logs import *
|
||||
from .Kick import *
|
||||
|
||||
|
||||
__author__ = 'Sam Zick'
|
||||
__email__ = 'sam@deathbybandaid.net'
|
||||
__version__ = '0.1.1'
|
||||
31
sopel_modules/SpiceBot_Core_Processing/osd.py
Normal file
31
sopel_modules/SpiceBot_Core_Processing/osd.py
Normal file
@ -0,0 +1,31 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
"""
|
||||
This is the SpiceBot OSD system.
|
||||
"""
|
||||
import sopel
|
||||
|
||||
|
||||
@sopel.module.event('005')
|
||||
@sopel.module.rule('.*')
|
||||
def parse_event_005(bot, trigger):
|
||||
if trigger.args[-1] != 'are supported by this server':
|
||||
return
|
||||
parameters = trigger.args[1:-1]
|
||||
for param in parameters:
|
||||
if '=' in param:
|
||||
if param.startswith("TARGMAX"):
|
||||
param = str(param).split('=')[1]
|
||||
settings = str(param).split(',')
|
||||
for setting in settings:
|
||||
settingname = str(setting).split(':')[0]
|
||||
if settingname.upper() in ['NOTICE', 'PRIVMSG']:
|
||||
try:
|
||||
value = str(setting).split(':')[1] or None
|
||||
except IndexError:
|
||||
value = None
|
||||
if value:
|
||||
if settingname.upper() == 'NOTICE':
|
||||
bot.config.SpiceBot_OSD.notice = int(value)
|
||||
elif settingname.upper() == 'PRIVMSG':
|
||||
bot.config.SpiceBot_OSD.privmsg = int(value)
|
||||
@ -1,120 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||
|
||||
# sopel imports
|
||||
import sopel.module
|
||||
from sopel.tools import Identifier
|
||||
from sopel.db import SopelDB, NickValues, ChannelValues
|
||||
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
import json
|
||||
|
||||
from sopel_modules.SpiceBot.Logs import botlogs
|
||||
|
||||
|
||||
def setup(bot):
|
||||
pass
|
||||
# Inject Database Functions
|
||||
botlogs.log('SpiceBot_Databaseaddons', "Implanting Database functions into bot")
|
||||
SopelDB.delete_nick_value = SopelDBCache.delete_nick_value
|
||||
SopelDB.adjust_nick_value = SopelDBCache.adjust_nick_value
|
||||
SopelDB.delete_channel_value = SopelDBCache.delete_channel_value
|
||||
SopelDB.adjust_channel_value = SopelDBCache.adjust_channel_value
|
||||
|
||||
|
||||
class SopelDBCache:
|
||||
|
||||
"""Nicks"""
|
||||
|
||||
def delete_nick_value(self, nick, key):
|
||||
"""Deletes the value for a given key to be associated with the nick."""
|
||||
nick = Identifier(nick)
|
||||
nick_id = self.get_nick_id(nick)
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(NickValues) \
|
||||
.filter(NickValues.nick_id == nick_id) \
|
||||
.filter(NickValues.key == key) \
|
||||
.one_or_none()
|
||||
# NickValue exists, delete
|
||||
if result:
|
||||
session.delete(result)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def adjust_nick_value(self, nick, key, value):
|
||||
"""Sets the value for a given key to be associated with the nick."""
|
||||
nick = Identifier(nick)
|
||||
value = json.dumps(value, ensure_ascii=False)
|
||||
nick_id = self.get_nick_id(nick)
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(NickValues) \
|
||||
.filter(NickValues.nick_id == nick_id) \
|
||||
.filter(NickValues.key == key) \
|
||||
.one_or_none()
|
||||
# NickValue exists, update
|
||||
if result:
|
||||
result.value = result.value + value
|
||||
session.commit()
|
||||
# DNE - Insert
|
||||
else:
|
||||
new_nickvalue = NickValues(nick_id=nick_id, key=key, value=value)
|
||||
session.add(new_nickvalue)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
"""Channels"""
|
||||
|
||||
def delete_channel_value(self, channel, key):
|
||||
"""Sets the value for a given key to be associated with the channel."""
|
||||
channel = Identifier(channel).lower()
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(ChannelValues) \
|
||||
.filter(ChannelValues.channel == channel)\
|
||||
.filter(ChannelValues.key == key) \
|
||||
.one_or_none()
|
||||
# ChannelValue exists, update
|
||||
if result:
|
||||
session.delete(result)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def adjust_channel_value(self, channel, key, value):
|
||||
"""Sets the value for a given key to be associated with the channel."""
|
||||
channel = Identifier(channel).lower()
|
||||
value = json.dumps(value, ensure_ascii=False)
|
||||
session = self.ssession()
|
||||
try:
|
||||
result = session.query(ChannelValues) \
|
||||
.filter(ChannelValues.channel == channel)\
|
||||
.filter(ChannelValues.key == key) \
|
||||
.one_or_none()
|
||||
# ChannelValue exists, update
|
||||
if result:
|
||||
result.value = result.value + value
|
||||
session.commit()
|
||||
# DNE - Insert
|
||||
else:
|
||||
new_channelvalue = ChannelValues(channel=channel, key=key, value=value)
|
||||
session.add(new_channelvalue)
|
||||
session.commit()
|
||||
except SQLAlchemyError:
|
||||
session.rollback()
|
||||
raise
|
||||
finally:
|
||||
session.close()
|
||||
@ -1,6 +0,0 @@
|
||||
# coding=utf-8
|
||||
"""Useful miscellaneous tools and shortcuts for SpiceBot Sopel modules
|
||||
"""
|
||||
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||
|
||||
from .Databaseaddons import *
|
||||
@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||
|
||||
# sopel imports
|
||||
import sopel.module
|
||||
|
||||
from sopel_modules.SpiceBot.Logs import botlogs
|
||||
|
||||
|
||||
def setup(bot):
|
||||
botlogs.log('SpiceBot_DatabaseCache', "Setting up Database Cache")
|
||||
if 'SpiceBot_DatabaseCache' not in bot.memory:
|
||||
bot.memory['SpiceBot_DatabaseCache'] = dict()
|
||||
|
||||
|
||||
def shutdown(bot):
|
||||
if "SpiceBot_DatabaseCache" in bot.memory:
|
||||
del bot.memory["SpiceBot_DatabaseCache"]
|
||||
@ -1,6 +0,0 @@
|
||||
# coding=utf-8
|
||||
"""Useful miscellaneous tools and shortcuts for SpiceBot Sopel modules
|
||||
"""
|
||||
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||
|
||||
from .DatabaseCache import *
|
||||
@ -1,57 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||
|
||||
# sopel imports
|
||||
import sopel.module
|
||||
|
||||
|
||||
"""Database Direct"""
|
||||
|
||||
|
||||
# Get a value
|
||||
def db_get_nick_value(bot, nick, key):
|
||||
database_value = bot.db.get_nick_value(nick, key) or None
|
||||
return database_value
|
||||
|
||||
|
||||
# set a value
|
||||
def db_set_nick_value(bot, nick, key, value):
|
||||
bot.db.set_nick_value(nick, key, value)
|
||||
|
||||
|
||||
# DELETE a value
|
||||
def db_reset_value(bot, nick, key):
|
||||
bot.db.reset_nick_value(nick, key)
|
||||
|
||||
|
||||
# add or subtract from current value
|
||||
def db_adjust_value(bot, nick, key, value):
|
||||
bot.db.adjust_nick_value(nick, key, value)
|
||||
|
||||
|
||||
# list stored in database, add or remove elements
|
||||
def db_adjust_list(bot, nick, entries, key, adjustmentdirection):
|
||||
if not isinstance(entries, list):
|
||||
entries = [entries]
|
||||
adjustlist = db_get_nick_value(bot, nick, key) or []
|
||||
adjustlistnew = []
|
||||
for x in adjustlist:
|
||||
adjustlistnew.append(x)
|
||||
db_reset_value(bot, nick, key)
|
||||
adjustlist = []
|
||||
if adjustmentdirection == 'add':
|
||||
for y in entries:
|
||||
if y not in adjustlistnew:
|
||||
adjustlistnew.append(y)
|
||||
elif adjustmentdirection == 'del':
|
||||
for y in entries:
|
||||
if y in adjustlistnew:
|
||||
adjustlistnew.remove(y)
|
||||
for x in adjustlistnew:
|
||||
if x not in adjustlist:
|
||||
adjustlist.append(x)
|
||||
if not len(adjustlist):
|
||||
db_reset_value(bot, nick, key)
|
||||
else:
|
||||
db_set_nick_value(bot, nick, key, adjustlist)
|
||||
@ -1,6 +0,0 @@
|
||||
# coding=utf-8
|
||||
"""Useful miscellaneous tools and shortcuts for SpiceBot Sopel modules
|
||||
"""
|
||||
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||
|
||||
from .DatabaseTools import *
|
||||
@ -1,12 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
from sopel_modules.SpiceBot_SBTools import github_dict
|
||||
|
||||
|
||||
@sopel.module.nickname_commands('help', 'docs', 'wiki')
|
||||
def bot_command_owners(bot, trigger):
|
||||
bot.osd(["IRC Modules Repository", str(github_dict["url_main"] + github_dict["repo_owner"] + "/" + github_dict["repo_name"] + github_dict["url_path_wiki"])])
|
||||
@ -1,8 +0,0 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
from .Docs import *
|
||||
|
||||
__author__ = 'Sam Zick'
|
||||
__email__ = 'sam@deathbybandaid.net'
|
||||
__version__ = '0.1.1'
|
||||
@ -1,16 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
|
||||
|
||||
@sopel.module.event(botevents.BOT_WELCOME)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_events_Connected(bot, trigger):
|
||||
"""Here, we wait until we are in at least one channel"""
|
||||
while not len(bot.channels.keys()) > 0:
|
||||
pass
|
||||
botevents.trigger(bot, botevents.BOT_CONNECTED, "Bot Connected to IRC")
|
||||
@ -1,15 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
|
||||
|
||||
@sopel.module.event(botevents.RPL_WELCOME)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_startup_welcome(bot, trigger):
|
||||
botevents.SpiceBot_Events["RPL_WELCOME_Count"] += 1
|
||||
if botevents.SpiceBot_Events["RPL_WELCOME_Count"] > 1:
|
||||
botevents.trigger(bot, botevents.BOT_RECONNECTED, "Bot ReConnected to IRC")
|
||||
@ -1,15 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
|
||||
|
||||
@botevents.startup_check_ready()
|
||||
@sopel.module.event(botevents.BOT_READY)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_events_startup_complete(bot, trigger):
|
||||
"""All events registered as required for startup have completed"""
|
||||
botevents.trigger(bot, botevents.BOT_LOADED, "All registered modules setup procedures have completed")
|
||||
@ -1,15 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
from sopel_modules.SpiceBot.Logs import botlogs
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
|
||||
|
||||
@sopel.module.event(botevents.BOT_WELCOME, botevents.BOT_READY, botevents.BOT_CONNECTED, botevents.BOT_LOADED)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_events_complete(bot, trigger):
|
||||
"""This is here simply to log to stderr that this was recieved."""
|
||||
botlogs.log('SpiceBot_Events', trigger.args[1], True)
|
||||
@ -1,18 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
|
||||
|
||||
@sopel.module.event(botevents.BOT_WELCOME)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_events_connected(bot, trigger):
|
||||
"""For items tossed in a queue, this will trigger them accordingly"""
|
||||
while True:
|
||||
if len(botevents.SpiceBot_Events["trigger_queue"]):
|
||||
pretriggerdict = botevents.SpiceBot_Events["trigger_queue"][0]
|
||||
botevents.dispatch(bot, pretriggerdict)
|
||||
del botevents.SpiceBot_Events["trigger_queue"][0]
|
||||
@ -1,14 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
|
||||
|
||||
@sopel.module.event(botevents.BOT_WELCOME)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_events_start(bot, trigger):
|
||||
"""This stage is redundant, but shows the system is working."""
|
||||
botevents.trigger(bot, botevents.BOT_READY, "Ready To Process module setup procedures")
|
||||
@ -1,17 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
|
||||
|
||||
@sopel.module.event(botevents.RPL_WELCOME)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_startup_welcome(bot, trigger):
|
||||
"""The Bot events system does not start until RPL_WELCOME 001 is recieved
|
||||
from the server"""
|
||||
if botevents.check(botevents.BOT_WELCOME):
|
||||
return
|
||||
botevents.trigger(bot, botevents.BOT_WELCOME, "Welcome to the SpiceBot Events System")
|
||||
@ -1,13 +0,0 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
from .Welcome import *
|
||||
from .Ready import *
|
||||
from .Connected import *
|
||||
from .Loaded import *
|
||||
from .Queue import *
|
||||
from .Logging import *
|
||||
|
||||
__author__ = 'Sam Zick'
|
||||
__email__ = 'sam@deathbybandaid.net'
|
||||
__version__ = '0.1.1'
|
||||
@ -1,10 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
|
||||
@sopel.module.nickname_commands('gender')
|
||||
def bot_command_gender(bot, trigger):
|
||||
bot.osd("If societal genders are binary, my gender is female")
|
||||
@ -1,8 +0,0 @@
|
||||
# coding=utf8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
from .Gender import *
|
||||
|
||||
__author__ = 'Sam Zick'
|
||||
__email__ = 'sam@deathbybandaid.net'
|
||||
__version__ = '0.1.1'
|
||||
@ -8,24 +8,22 @@ import sopel.module
|
||||
|
||||
import spicemanip
|
||||
|
||||
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@botevents.check_ready([botevents.BOT_GIFSEARCH])
|
||||
@SpiceBot.events.check_ready([SpiceBot.events.BOT_GIFSEARCH])
|
||||
@SpiceBot.prerun.prerun('prefix')
|
||||
@sopel.module.commands('(.*)')
|
||||
def gifapi_triggers(bot, trigger):
|
||||
|
||||
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'prefix_command')
|
||||
|
||||
if triggercommand not in bot.memory["SpiceBot_GifSearch"]['valid_gif_api_dict'].keys():
|
||||
if trigger.sb['com'] not in bot.memory["SpiceBot_GifSearch"]['valid_gif_api_dict'].keys():
|
||||
return
|
||||
|
||||
if not len(triggerargs):
|
||||
if not len(trigger.sb['args']):
|
||||
return bot.osd("Please present a query to search.")
|
||||
|
||||
query = spicemanip.main(triggerargs, 0)
|
||||
searchdict = {"query": query, "gifsearch": triggercommand}
|
||||
query = spicemanip.main(trigger.sb['args'], 0)
|
||||
searchdict = {"query": query, "gifsearch": trigger.sb['com']}
|
||||
|
||||
gifdict = getGif(bot, searchdict)
|
||||
|
||||
@ -6,21 +6,20 @@ from sopel import module
|
||||
|
||||
from .gifsearch import getGif
|
||||
|
||||
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
import spicemanip
|
||||
|
||||
|
||||
@botevents.check_ready([botevents.BOT_GIFSEARCH])
|
||||
@SpiceBot.events.check_ready([SpiceBot.events.BOT_GIFSEARCH])
|
||||
@SpiceBot.prerun.prerun('prefix')
|
||||
@module.commands('gif')
|
||||
def gif_trigger(bot, trigger):
|
||||
|
||||
triggerargs, triggercommand = sopel_triggerargs(bot, trigger)
|
||||
if not len(triggerargs):
|
||||
if not len(trigger.sb['args']):
|
||||
return bot.osd("Please present a query to search.")
|
||||
|
||||
query = spicemanip.main(triggerargs, 0)
|
||||
query = spicemanip.main(trigger.sb['args'], 0)
|
||||
searchapis = bot.memory["SpiceBot_GifSearch"]['valid_gif_api_dict'].keys()
|
||||
searchdict = {"query": query, "gifsearch": searchapis}
|
||||
|
||||
33
sopel_modules/SpiceBot_GifSearch/Gif_Search_Commands
Normal file
33
sopel_modules/SpiceBot_GifSearch/Gif_Search_Commands
Normal file
@ -0,0 +1,33 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
from .gifsearch import getGif
|
||||
|
||||
import sopel.module
|
||||
|
||||
import spicemanip
|
||||
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
|
||||
@SpiceBot.events.check_ready([SpiceBot.events.BOT_GIFSEARCH])
|
||||
@SpiceBot.prerun.prerun('prefix')
|
||||
@sopel.module.commands('(.*)')
|
||||
def gifapi_triggers(bot, trigger):
|
||||
|
||||
if trigger.sb['com'] not in bot.memory["SpiceBot_GifSearch"]['valid_gif_api_dict'].keys():
|
||||
return
|
||||
|
||||
if not len(trigger.sb['args']):
|
||||
return bot.osd("Please present a query to search.")
|
||||
|
||||
query = spicemanip.main(trigger.sb['args'], 0)
|
||||
searchdict = {"query": query, "gifsearch": trigger.sb['com']}
|
||||
|
||||
gifdict = getGif(bot, searchdict)
|
||||
|
||||
if gifdict["error"]:
|
||||
bot.osd(gifdict["error"])
|
||||
else:
|
||||
bot.osd(str(gifdict['gifapi'].title() + " Result (" + str(query) + " #" + str(gifdict["returnnum"]) + "): " + str(gifdict["returnurl"])))
|
||||
@ -5,8 +5,9 @@ Sopel Gif Search builds a convenient framework for searching for Gifs
|
||||
"""
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
from .gif import *
|
||||
from .gifapi import *
|
||||
from .Gif_Command import *
|
||||
from .Gif_API_Commands import *
|
||||
# from .Gif_Search_Commands import *
|
||||
from .gifsearch import *
|
||||
|
||||
__author__ = 'Sam Zick'
|
||||
|
||||
@ -5,10 +5,7 @@ from __future__ import unicode_literals, absolute_import, division, print_functi
|
||||
import sopel.module
|
||||
from sopel.config.types import StaticSection, ValidatedAttribute
|
||||
|
||||
from sopel_modules.SpiceBot.Logs import botlogs
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
from sopel_modules.SpiceBot_CommandsQuery.CommandsQuery import commandsquery_register
|
||||
from sopel_modules.SpiceBot_SBTools import read_directory_json_to_dict
|
||||
import sopel_modules.SpiceBot as SpiceBot
|
||||
|
||||
import spicemanip
|
||||
|
||||
@ -32,7 +29,7 @@ class GifAPISection(StaticSection):
|
||||
def configure(config):
|
||||
moduledir = os.path.dirname(os.path.abspath(__file__))
|
||||
api_dir = os.path.join(moduledir, 'gifapi')
|
||||
valid_gif_api_dict = read_directory_json_to_dict(None, [api_dir], "Gif API", "SpiceBot_GifSearch")
|
||||
valid_gif_api_dict = SpiceBot.read_directory_json_to_dict([api_dir], "Gif API", "SpiceBot_GifSearch", logging=True)
|
||||
|
||||
config.define_section("SopelGifSearch", GifAPIMainSection, validate=False)
|
||||
config.SopelGifSearch.configure_setting('extra', 'SpiceBot_GifSearch API Extra directory')
|
||||
@ -45,8 +42,8 @@ def configure(config):
|
||||
|
||||
|
||||
def setup(bot):
|
||||
botlogs.log('SpiceBot_GifSearch', "Starting Setup Procedure")
|
||||
botevents.startup_add([botevents.BOT_GIFSEARCH])
|
||||
SpiceBot.logs.log('SpiceBot_GifSearch', "Starting Setup Procedure")
|
||||
SpiceBot.events.startup_add([SpiceBot.events.BOT_GIFSEARCH])
|
||||
|
||||
if 'SpiceBot_GifSearch' not in bot.memory:
|
||||
bot.memory["SpiceBot_GifSearch"] = {"cache": {}, "badgiflinks": [], 'valid_gif_api_dict': {}}
|
||||
@ -58,13 +55,15 @@ def setup(bot):
|
||||
dir_to_scan.append(api_dir)
|
||||
|
||||
bot.config.define_section("SopelGifSearch", GifAPIMainSection, validate=False)
|
||||
SpiceBot.config.define_section("SopelGifSearch", GifAPIMainSection, validate=False)
|
||||
if bot.config.SopelGifSearch.extra:
|
||||
dir_to_scan.append(bot.config.SopelGifSearch.extra)
|
||||
|
||||
valid_gif_api_dict = read_directory_json_to_dict(bot, dir_to_scan, "Gif API", "SpiceBot_GifSearch")
|
||||
valid_gif_api_dict = SpiceBot.read_directory_json_to_dict(dir_to_scan, "Gif API", "SpiceBot_GifSearch", logging=True)
|
||||
|
||||
for gif_api in valid_gif_api_dict.keys():
|
||||
bot.config.define_section(gif_api, GifAPISection, validate=False)
|
||||
SpiceBot.config.define_section(gif_api, GifAPISection, validate=False)
|
||||
apikey = eval("bot.config." + gif_api + ".apikey")
|
||||
if apikey:
|
||||
valid_gif_api_dict[gif_api]["apikey"] = apikey
|
||||
@ -73,12 +72,17 @@ def setup(bot):
|
||||
bot.memory["SpiceBot_GifSearch"]['valid_gif_api_dict'][gif_api] = valid_gif_api_dict[gif_api]
|
||||
|
||||
for validgifapi in bot.memory["SpiceBot_GifSearch"]['valid_gif_api_dict'].keys():
|
||||
commandsquery_register(bot, "prefix", validgifapi)
|
||||
command_dict = {
|
||||
"comtype": "prefix",
|
||||
"validcoms": validgifapi
|
||||
}
|
||||
SpiceBot.commands.dict['counts'] += 1
|
||||
SpiceBot.commands.register(command_dict)
|
||||
|
||||
if validgifapi not in bot.memory["SpiceBot_GifSearch"]['cache'].keys():
|
||||
bot.memory["SpiceBot_GifSearch"]['cache'][validgifapi] = dict()
|
||||
|
||||
botevents.trigger(bot, botevents.BOT_GIFSEARCH, "SpiceBot_GifSearch")
|
||||
SpiceBot.events.trigger(bot, SpiceBot.events.BOT_GIFSEARCH, "SpiceBot_GifSearch")
|
||||
|
||||
|
||||
def shutdown(bot):
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
# coding=utf-8
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
|
||||
|
||||
def setup(bot):
|
||||
if 'SpiceBot_InvalidCommand' not in bot.memory:
|
||||
bot.memory["SpiceBot_InvalidCommand"] = {"valid": []}
|
||||
|
||||
|
||||
def shutdown(bot):
|
||||
if "SpiceBot_InvalidCommand" in bot.memory:
|
||||
del bot.memory["SpiceBot_InvalidCommand"]
|
||||
|
||||
|
||||
@sopel.module.event(botevents.BOT_LOADED)
|
||||
@sopel.module.rule('.*')
|
||||
def bot_events_complete(bot, trigger):
|
||||
for comtype in bot.memory['SpiceBot_CommandsQuery']['commands'].keys():
|
||||
bot.memory["SpiceBot_InvalidCommand"]["valid"].extend(bot.memory['SpiceBot_CommandsQuery']['commands'][comtype].keys())
|
||||
|
||||
|
||||
@botevents.check_ready([botevents.BOT_LOADED, botevents.BOT_COMMANDSQUERY])
|
||||
@sopel.module.commands('(.*)')
|
||||
def InvalidCommand_triggers(bot, trigger):
|
||||
return
|
||||
|
||||
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'prefix_command')
|
||||
|
||||
# patch for people typing "...", maybe other stuff, but this verifies that there is still a command here
|
||||
if triggercommand.startswith("."):
|
||||
return
|
||||
|
||||
if triggercommand not in bot.memory["SpiceBot_InvalidCommand"]["valid"]:
|
||||
invalid_display = ["I don't seem to have a command for " + str(triggercommand) + "!"]
|
||||
invalid_display.append("If you have a suggestion for this command, you can run .feature ." + str(triggercommand))
|
||||
invalid_display.append("ADD DESCRIPTION HERE!")
|
||||
bot.osd(invalid_display, trigger.nick, 'notice')
|
||||
@ -1,12 +0,0 @@
|
||||
# coding=utf8
|
||||
"""Sopel Gif Search
|
||||
|
||||
Sopel Gif Search builds a convenient framework for searching for Gifs
|
||||
"""
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
from .InvalidCommand import *
|
||||
|
||||
__author__ = 'Sam Zick'
|
||||
__email__ = 'sam@deathbybandaid.net'
|
||||
__version__ = '0.1.1'
|
||||
@ -1,96 +0,0 @@
|
||||
# coding=utf8
|
||||
"""Sopel Kick
|
||||
|
||||
Sopel Kick is an easy way to kick users from channels
|
||||
"""
|
||||
|
||||
# pylama:ignore=W0611
|
||||
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.bot
|
||||
from sopel import tools, module
|
||||
from sopel.tools import Identifier
|
||||
from sopel.config.types import StaticSection, ValidatedAttribute
|
||||
|
||||
from sopel_modules.SpiceBot.Logs import botlogs
|
||||
|
||||
|
||||
import time
|
||||
from collections import abc
|
||||
import sys
|
||||
|
||||
|
||||
__author__ = 'Sam Zick'
|
||||
__email__ = 'sam@deathbybandaid.net'
|
||||
__version__ = '0.1.2'
|
||||
|
||||
|
||||
def configure(config):
|
||||
config.define_section("SpiceBot_Kick", SpiceBot_Kick, validate=False)
|
||||
config.SpiceBot_Kick.configure_setting('kick', 'MAXTARG limit for KICK')
|
||||
|
||||
|
||||
def setup(bot):
|
||||
|
||||
# Inject KICK
|
||||
botlogs.log('SpiceBot_Kick', "Implanting Kick function into bot")
|
||||
bot.kick = SopelKICK.kick
|
||||
sopel.bot.SopelWrapper.kick = SopelWrapperKICK.kick
|
||||
|
||||
# verify config settings for server
|
||||
botlogs.log('SpiceBot_Kick', "Checking for config settings")
|
||||
bot.config.define_section("SpiceBot_Kick", SpiceBot_Kick, validate=False)
|
||||
|
||||
|
||||
@module.event('005')
|
||||
@module.rule('.*')
|
||||
def parse_event_005(bot, trigger):
|
||||
if trigger.args[-1] != 'are supported by this server':
|
||||
return
|
||||
parameters = trigger.args[1:-1]
|
||||
for param in parameters:
|
||||
if '=' in param:
|
||||
if param.startswith("TARGMAX"):
|
||||
param = str(param).split('=')[1]
|
||||
settings = str(param).split(',')
|
||||
for setting in settings:
|
||||
settingname = str(setting).split(':')[0]
|
||||
if settingname.upper() in ['KICK']:
|
||||
try:
|
||||
value = str(setting).split(':')[1] or None
|
||||
except IndexError:
|
||||
value = None
|
||||
if value:
|
||||
bot.config.SpiceBot_Kick.kick = int(value)
|
||||
|
||||
|
||||
class SpiceBot_Kick(StaticSection):
|
||||
kick = ValidatedAttribute('kick', default=1)
|
||||
|
||||
|
||||
class SopelKICK:
|
||||
|
||||
def kick(self, nick, channel, text=None):
|
||||
"""Send an IRC KICK command.
|
||||
Within the context of a triggered callable, ``channel`` will default to the
|
||||
channel in which the call was triggered. If triggered from a private message,
|
||||
``channel`` is required (or the call to ``kick()`` will be ignored).
|
||||
The bot must be a channel operator in specified channel for this to work.
|
||||
.. versionadded:: 7.0
|
||||
"""
|
||||
self.write(['KICK', channel, nick], text)
|
||||
|
||||
|
||||
class SopelWrapperKICK(object):
|
||||
|
||||
def kick(self, nick, channel=None, message=None):
|
||||
if channel is None:
|
||||
if self._trigger.is_privmsg:
|
||||
raise RuntimeError('Error: KICK requires a channel.')
|
||||
else:
|
||||
channel = self._trigger.sender
|
||||
if nick is None:
|
||||
raise RuntimeError('Error: KICK requires a nick.')
|
||||
self._bot.kick(nick, channel, message)
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,53 +0,0 @@
|
||||
# coding=utf-8
|
||||
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||
|
||||
import sopel.module
|
||||
|
||||
import spicemanip
|
||||
|
||||
from sopel_modules.SpiceBot.Logs import botlogs
|
||||
from sopel_modules.SpiceBot.Events import botevents
|
||||
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, command_permissions_check, inlist, inlist_match, similar_list
|
||||
|
||||
|
||||
@botevents.check_ready([botevents.BOT_LOGS])
|
||||
@sopel.module.nickname_commands('logs', 'debug')
|
||||
def bot_command_logs(bot, trigger):
|
||||
|
||||
if not command_permissions_check(bot, trigger, ['admins', 'owner', 'OP', 'ADMIN', 'OWNER']):
|
||||
bot.say("I was unable to process this Bot Nick command due to privilege issues.")
|
||||
return
|
||||
|
||||
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'nickname_command')
|
||||
|
||||
logtype = spicemanip.main(triggerargs, 1) or None
|
||||
if not logtype:
|
||||
bot.osd("Current valid log(s) include: " + spicemanip.main(botlogs.SpiceBot_Logs["list"].keys(), 'andlist'), trigger.sender, 'action')
|
||||
return
|
||||
|
||||
if not inlist(bot, logtype, botlogs.SpiceBot_Logs["list"].keys()):
|
||||
closestmatches = similar_list(bot, logtype, botlogs.SpiceBot_Logs["list"].keys(), 10, 'reverse')
|
||||
if not len(closestmatches):
|
||||
bot.notice("No valid logs match " + str(logtype) + ".", trigger.nick)
|
||||
else:
|
||||
bot.notice("The following commands may match " + str(logtype) + ": " + spicemanip.main(closestmatches, 'andlist') + ".", trigger.nick)
|
||||
|
||||
return
|
||||
|
||||
logtype = inlist_match(bot, logtype, botlogs.SpiceBot_Logs["list"].keys())
|
||||
|
||||
if logtype == "Sopel_systemd":
|
||||
logindex = botlogs.systemd_logs_fetch(bot)
|
||||
elif logtype == "Sopel_stdio":
|
||||
logindex = botlogs.stdio_logs_fetch(bot)
|
||||
else:
|
||||
logindex = botlogs.SpiceBot_Logs["list"][logtype]
|
||||
|
||||
if not len(logindex):
|
||||
bot.osd("No logs found for " + str(logtype) + ".")
|
||||
return
|
||||
|
||||
bot.osd("Is Examining " + str(logtype) + " log(s).")
|
||||
for line in logindex:
|
||||
bot.osd(" " + str(line))
|
||||
bot.osd(str(logtype) + " log(s) Complete.")
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user