mirror of
https://github.com/SpiceBot/SpiceBot.git
synced 2026-11-11 06:00:59 -05:00
367 lines
14 KiB
Python
367 lines
14 KiB
Python
# 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 os
|
|
import threading
|
|
|
|
import spicemanip
|
|
|
|
from .Logs import logs
|
|
from .Config import config as botconfig
|
|
from .Database import db as botdb
|
|
from .Events import events
|
|
from .Prerun import prerun
|
|
from .Tools import letters_in_string, similar_list
|
|
|
|
|
|
class BotCommands():
|
|
"""This Logs all commands known to the bot"""
|
|
def __init__(self):
|
|
self.lock = threading.Lock()
|
|
self.dict = {
|
|
"counts": 0,
|
|
"commands": {
|
|
'module': {},
|
|
'nickname': {},
|
|
'rule': {}
|
|
},
|
|
'disabled': {}
|
|
}
|
|
|
|
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_CommandsQuery', "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()
|
|
|
|
|
|
@events.check_ready([events.BOT_COMMANDSQUERY])
|
|
@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 letters_in_string(trigger.sb['com']):
|
|
return
|
|
|
|
commands_list = dict()
|
|
for com in commands.dict['commands']['nickname'].keys():
|
|
if com not in commands_list.keys():
|
|
commands_list[com] = 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 = 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 = 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')
|
|
|
|
|
|
@events.check_ready([events.BOT_COMMANDSQUERY])
|
|
@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 letters_in_string(trigger.sb['com']):
|
|
return
|
|
|
|
commands_list = dict()
|
|
for commandstype in commands.dict['commands'].keys():
|
|
if commandstype not in ['rule', 'nickname']:
|
|
for com in commands.dict['commands'][commandstype].keys():
|
|
if com not in commands_list.keys():
|
|
commands_list[com] = 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 = 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 = 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')
|