Merge branch 'development' of https://github.com/deathbybandaid/SpiceBot into development

This commit is contained in:
deathbybandaid 2019-05-15 21:42:38 -04:00
commit 35a491b202
24 changed files with 530 additions and 371 deletions

View File

@ -20,7 +20,8 @@ rm dev-requirements.txt
wget https://raw.githubusercontent.com/SpiceBot/SpiceBot/development/Installation%20Files/requirements.txt wget https://raw.githubusercontent.com/SpiceBot/SpiceBot/development/Installation%20Files/requirements.txt
pip3 install -r requirements.txt pip3 install -r requirements.txt
rm requirements.txt rm requirements.txt
pip3 install sopel # pip3 install sopel
pip3 install --upgrade --force-reinstall git+https://github.com/sopel-irc/sopel@master
mkdir /usr/local/lib/python3.6/dist-packages/sopel/modules/stock mkdir /usr/local/lib/python3.6/dist-packages/sopel/modules/stock
mv /usr/local/lib/python3.6/dist-packages/sopel/modules/* /usr/local/lib/python3.6/dist-packages/sopel/modules/stock/ mv /usr/local/lib/python3.6/dist-packages/sopel/modules/* /usr/local/lib/python3.6/dist-packages/sopel/modules/stock/
@ -39,6 +40,9 @@ mkdir /run/sopel
echo $$ > /run/sopel/sopel-SpiceBotSERV.pid echo $$ > /run/sopel/sopel-SpiceBotSERV.pid
chmod -R 777 /run/sopel/ chmod -R 777 /run/sopel/
apt install mysql-server libmysqlclient-dev -y
pip3 install mysql
cp /home/sopel/SpiceBot/System-Files/Config/SpiceBot.cfg /home/sopel/SpiceBot.cfg cp /home/sopel/SpiceBot/System-Files/Config/SpiceBot.cfg /home/sopel/SpiceBot.cfg
cp /home/sopel/SpiceBot/System-Files/systemd/SpiceBot.service /lib/systemd/system/SpiceBot.service cp /home/sopel/SpiceBot/System-Files/systemd/SpiceBot.service /lib/systemd/system/SpiceBot.service

View File

@ -7,20 +7,24 @@ import sopel.module
import spicemanip import spicemanip
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, googlesearch, bot_privs, inlist, inlist_match, similar_list from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, googlesearch, bot_privs, inlist, inlist_match, similar_list
from sopel_modules.SpiceBot_Events.System import bot_events_check from sopel_modules.SpiceBot_Events.System import botevents
@botevents.check_ready([botevents.BOT_LOADED, botevents.BOT_COMMANDSQUERY])
@sopel.module.nickname_commands('(.*)') @sopel.module.nickname_commands('(.*)')
def bot_command_nick(bot, trigger): def bot_command_nick(bot, trigger):
while not bot_events_check(bot, ['1004', '2002']): # while not botevents.check([botevents.BOT_LOADED, botevents.BOT_COMMANDSQUERY]):
pass # pass
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'nickname_command') triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'nickname_command')
if not triggercommand: if not triggercommand:
return return
if triggercommand[0] == "?":
return
if triggercommand in bot.memory['SpiceBot_CommandsQuery']['commands']["nickname"].keys(): if triggercommand in bot.memory['SpiceBot_CommandsQuery']['commands']["nickname"].keys():
return return
triggerargs.insert(0, triggercommand) triggerargs.insert(0, triggercommand)

View File

@ -6,8 +6,7 @@ from __future__ import unicode_literals, absolute_import, print_function, divisi
import sopel.module import sopel.module
from sopel.config.types import StaticSection, ValidatedAttribute, ListAttribute from sopel.config.types import StaticSection, ValidatedAttribute, ListAttribute
from sopel_modules.SpiceBot_Events.System import bot_events_startup_register, bot_events_recieved, bot_events_trigger from sopel_modules.SpiceBot_Events.System import botevents
from sopel_modules.SpiceBot_SBTools import ( from sopel_modules.SpiceBot_SBTools import (
join_all_channels, chanadmin_all_channels, channel_list_current, join_all_channels, chanadmin_all_channels, channel_list_current,
bot_logging bot_logging
@ -35,7 +34,7 @@ def configure(config):
def setup(bot): def setup(bot):
bot_logging(bot, 'SpiceBot_Channels', "Starting setup procedure") bot_logging(bot, 'SpiceBot_Channels', "Starting setup procedure")
bot_events_startup_register(bot, ['2001']) botevents.startup_add([botevents.BOT_CHANNELS])
bot.config.define_section("SpiceBot_Channels", SpiceBot_Channels_MainSection, validate=False) bot.config.define_section("SpiceBot_Channels", SpiceBot_Channels_MainSection, validate=False)
@ -48,10 +47,10 @@ def shutdown(bot):
del bot.memory["SpiceBot_Channels"] del bot.memory["SpiceBot_Channels"]
@sopel.module.event('1003') @sopel.module.event(botevents.BOT_CONNECTED)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def trigger_channel_list_initial(bot, trigger): def trigger_channel_list_initial(bot, trigger):
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)
# Unkickable # Unkickable
bot.write(('SAMODE', bot.nick, '+q')) bot.write(('SAMODE', bot.nick, '+q'))
@ -75,7 +74,7 @@ def trigger_channel_list_initial(bot, trigger):
channel_list_current(bot) channel_list_current(bot)
foundchannelcount = len(bot.memory['SpiceBot_Channels']['channels'].keys()) foundchannelcount = len(bot.memory['SpiceBot_Channels']['channels'].keys())
bot_logging(bot, 'SpiceBot_Channels', "Channel listing finished! " + str(foundchannelcount) + " channel(s) found.") bot_logging(bot, 'SpiceBot_Channels', "Channel listing finished! " + str(foundchannelcount) + " channel(s) found.")
bot_events_trigger(bot, 2001, "SpiceBot_Channels") botevents.trigger(bot, botevents.BOT_CHANNELS, "SpiceBot_Channels")
join_all_channels(bot) join_all_channels(bot)
chanadmin_all_channels(bot) chanadmin_all_channels(bot)
@ -124,7 +123,7 @@ def bot_part_empty(bot):
del bot.memory['SpiceBot_Channels']['channels'][channel.lower()] del bot.memory['SpiceBot_Channels']['channels'][channel.lower()]
@sopel.module.event('2001') @sopel.module.event(botevents.BOT_CHANNELS)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_events_setup(bot, trigger): def bot_events_setup(bot, trigger):
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)

View File

@ -6,7 +6,7 @@ import sopel.module
import spicemanip import spicemanip
from sopel_modules.SpiceBot_Events.System import bot_events_check from sopel_modules.SpiceBot_Events.System import botevents
from sopel_modules.SpiceBot_SBTools import ( from sopel_modules.SpiceBot_SBTools import (
sopel_triggerargs, inlist, channel_privs, sopel_triggerargs, inlist, channel_privs,
join_all_channels, channel_list_current, join_all_channels, channel_list_current,
@ -14,11 +14,12 @@ from sopel_modules.SpiceBot_SBTools import (
from .Channels import bot_part_empty from .Channels import bot_part_empty
@botevents.check_ready([botevents.BOT_LOADED])
@sopel.module.nickname_commands('channels', 'channel') @sopel.module.nickname_commands('channels', 'channel')
def nickname_comand_channels(bot, trigger): def nickname_comand_channels(bot, trigger):
while not bot_events_check(bot, '1004'): # while not botevents.check(botevents.BOT_LOADED):
pass # pass
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'nickname_command') triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'nickname_command')

View File

@ -7,7 +7,7 @@ import sopel.module
import os import os
from sopel_modules.SpiceBot_Events.System import bot_events_startup_register, bot_events_recieved, bot_events_trigger from sopel_modules.SpiceBot_Events.System import botevents
from sopel_modules.SpiceBot_SBTools import bot_logging from sopel_modules.SpiceBot_SBTools import bot_logging
import spicemanip import spicemanip
@ -15,7 +15,7 @@ import spicemanip
def setup(bot): def setup(bot):
bot_logging(bot, 'SpiceBot_CommandsQuery', "Starting setup procedure") bot_logging(bot, 'SpiceBot_CommandsQuery', "Starting setup procedure")
bot_events_startup_register(bot, ['2002']) botevents.startup_add([botevents.BOT_COMMANDSQUERY])
if 'SpiceBot_CommandsQuery' not in bot.memory: if 'SpiceBot_CommandsQuery' not in bot.memory:
bot.memory['SpiceBot_CommandsQuery'] = {"counts": 0, "commands": {}, "nickrules": []} bot.memory['SpiceBot_CommandsQuery'] = {"counts": 0, "commands": {}, "nickrules": []}
@ -97,9 +97,9 @@ def setup(bot):
detected_lines.append(line) detected_lines.append(line)
if len(detected_lines): if len(detected_lines):
bot.memory['SpiceBot_CommandsQuery']['counts'] += 1
filelinelist = [] filelinelist = []
currentsuccesslines = 0
for detected_line in detected_lines: for detected_line in detected_lines:
# Commands # Commands
@ -117,31 +117,41 @@ def setup(bot):
validcoms = list(validcoms) validcoms = list(validcoms)
else: else:
validcoms = [validcoms] validcoms = [validcoms]
for regexcom in ["(.*)", '^\?(.*)']:
if regexcom in validcoms:
while regexcom in validcoms:
validcoms.remove(regexcom)
validcomdict = {"comtype": comtype, "validcoms": validcoms} if len(validcoms):
filelinelist.append(validcomdict) validcomdict = {"comtype": comtype, "validcoms": validcoms}
filelinelist.append(validcomdict)
currentsuccesslines += 1
for atlinefound in filelinelist: if currentsuccesslines:
bot.memory['SpiceBot_CommandsQuery']['counts'] += 1
dict_from_file = dict() if len(filelinelist):
for atlinefound in filelinelist:
comtype = atlinefound["comtype"] dict_from_file = dict()
validcoms = atlinefound["validcoms"]
# default command to filename comtype = atlinefound["comtype"]
if "validcoms" not in dict_from_file.keys(): validcoms = atlinefound["validcoms"]
dict_from_file["validcoms"] = validcoms
maincom = dict_from_file["validcoms"][0] # default command to filename
if len(dict_from_file["validcoms"]) > 1: if "validcoms" not in dict_from_file.keys():
comaliases = spicemanip.main(dict_from_file["validcoms"], '2+', 'list') dict_from_file["validcoms"] = validcoms
else:
comaliases = []
bot.memory['SpiceBot_CommandsQuery']['commands'][comtype][maincom] = dict_from_file maincom = dict_from_file["validcoms"][0]
for comalias in comaliases: if len(dict_from_file["validcoms"]) > 1:
if comalias not in bot.memory['SpiceBot_CommandsQuery']['commands'][comtype].keys(): comaliases = spicemanip.main(dict_from_file["validcoms"], '2+', 'list')
bot.memory['SpiceBot_CommandsQuery']['commands'][comtype][comalias] = {"aliasfor": maincom} 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']: for comtype in ['module', 'nickname', 'rule']:
bot_logging(bot, 'SpiceBot_CommandsQuery', "Found " + str(len(bot.memory['SpiceBot_CommandsQuery']['commands'][comtype].keys())) + " " + comtype + " commands.", True) bot_logging(bot, 'SpiceBot_CommandsQuery', "Found " + str(len(bot.memory['SpiceBot_CommandsQuery']['commands'][comtype].keys())) + " " + comtype + " commands.", True)
@ -152,7 +162,7 @@ def setup(bot):
if command not in bot.memory['SpiceBot_CommandsQuery']['nickrules']: if command not in bot.memory['SpiceBot_CommandsQuery']['nickrules']:
bot.memory['SpiceBot_CommandsQuery']['nickrules'].append(command) bot.memory['SpiceBot_CommandsQuery']['nickrules'].append(command)
bot_events_trigger(bot, 2002, "SpiceBot_CommandsQuery") botevents.trigger(bot, botevents.BOT_COMMANDSQUERY, "SpiceBot_CommandsQuery")
def shutdown(bot): def shutdown(bot):
@ -160,10 +170,10 @@ def shutdown(bot):
del bot.memory["SpiceBot_CommandsQuery"] del bot.memory["SpiceBot_CommandsQuery"]
@sopel.module.event('1004') @sopel.module.event(botevents.BOT_LOADED)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_events_complete(bot, trigger): def bot_events_complete(bot, trigger):
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)
for comtype in bot.memory['SpiceBot_CommandsQuery']['commands'].keys(): for comtype in bot.memory['SpiceBot_CommandsQuery']['commands'].keys():
if comtype not in ['module', 'nickname', 'rule']: if comtype not in ['module', 'nickname', 'rule']:
@ -204,7 +214,7 @@ def commandsquery_register(bot, command_type, validcoms, aliasfor=None):
bot.memory['SpiceBot_CommandsQuery']['commands'][command_type][comalias] = {"aliasfor": aliasfor} bot.memory['SpiceBot_CommandsQuery']['commands'][command_type][comalias] = {"aliasfor": aliasfor}
@sopel.module.event('2002') @sopel.module.event(botevents.BOT_COMMANDSQUERY)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_events_setup(bot, trigger): def bot_events_setup(bot, trigger):
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)

View File

@ -0,0 +1,82 @@
# coding=utf-8
from __future__ import unicode_literals, absolute_import, division, print_function
import sopel
import sopel.module
from sopel_modules.SpiceBot_Events.System 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):
# while not botevents.check(botevents.BOT_COMMANDSQUERY):
# pass
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)

View File

@ -5,90 +5,76 @@ from __future__ import unicode_literals, absolute_import, division, print_functi
import sopel import sopel
import sopel.module import sopel.module
from difflib import SequenceMatcher from sopel_modules.SpiceBot_Events.System import botevents
from operator import itemgetter from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, similar_list, letters_in_string
from sopel_modules.SpiceBot_Events.System import bot_events_check
import spicemanip import spicemanip
@botevents.check_ready([botevents.BOT_COMMANDSQUERY])
@sopel.module.rule('^\?(.*)') @sopel.module.rule('^\?(.*)')
def query_detection(bot, trigger): def query_detection(bot, trigger):
while not bot_events_check(bot, '2002'): # while not botevents.check(botevents.BOT_COMMANDSQUERY):
pass # pass
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() commands_list = dict()
for commandstype in bot.memory['SpiceBot_CommandsQuery']['commands'].keys(): for commandstype in bot.memory['SpiceBot_CommandsQuery']['commands'].keys():
if commandstype != 'rule': if commandstype not in ['rule', 'nickname']:
for com in bot.memory['SpiceBot_CommandsQuery']['commands'][commandstype].keys(): for com in bot.memory['SpiceBot_CommandsQuery']['commands'][commandstype].keys():
if com not in commands_list.keys(): if com not in commands_list.keys():
if commandstype == 'nickname': commands_list[com] = bot.memory['SpiceBot_CommandsQuery']['commands'][commandstype][com]
commands_list[str(bot.nick) + " " + com] = bot.memory['SpiceBot_CommandsQuery']['commands'][commandstype][com]
else:
commands_list[com] = bot.memory['SpiceBot_CommandsQuery']['commands'][commandstype][com]
triggerargsarray = spicemanip.main(trigger, 'create') if triggercommand[:-1] == "+":
# command issued, check if valid triggercommand = triggercommand[:-1]
querycommand = spicemanip.main(triggerargsarray, 1).lower()[1:] if not triggercommand or not len(triggercommand):
if len(querycommand) == 1:
commandlist = []
for command in commands_list.keys():
if command.lower().startswith(querycommand):
commandlist.append(command)
if commandlist == []:
bot.notice("No commands match " + str(querycommand) + ".", trigger.nick)
return
else:
bot.notice("The following commands match " + str(querycommand) + ": " + spicemanip.main(commandlist, 'andlist') + ".", trigger.nick)
return return
elif querycommand.endswith(tuple(["+"])): if triggercommand.lower() not in list(commands_list.keys()):
querycommand = querycommand[:-1] dispmsg = ["Cannot find any alias commands: No valid commands match " + str(triggercommand) + "."]
if querycommand not in commands_list.keys(): closestmatches = similar_list(bot, triggercommand, list(commands_list.keys()), 10, 'reverse')
bot.notice("The " + str(querycommand) + " does not appear to be valid.") if len(closestmatches):
dispmsg.append("The following commands match " + str(triggercommand) + ": " + spicemanip.main(closestmatches, 'andlist') + ".")
bot.notice(dispmsg, trigger.nick)
return return
realcom = querycommand
if "aliasfor" in commands_list[querycommand].keys(): realcom = triggercommand
realcom = commands_list[querycommand]["aliasfor"] if "aliasfor" in commands_list[triggercommand].keys():
realcom = commands_list[triggercommand]["aliasfor"]
validcomlist = commands_list[realcom]["validcoms"] validcomlist = commands_list[realcom]["validcoms"]
bot.notice("The following commands match " + str(querycommand) + ": " + spicemanip.main(validcomlist, 'andlist') + ".", trigger.nick) bot.notice("The following commands match " + str(triggercommand) + ": " + spicemanip.main(validcomlist, 'andlist') + ".", trigger.nick)
return return
elif querycommand.endswith(tuple(['?'])): if triggercommand[:-1] == "?":
querycommand = querycommand[:-1]
sim_com, sim_num = [], []
for com in commands_list.keys():
similarlevel = SequenceMatcher(None, querycommand.lower(), com.lower()).ratio()
sim_com.append(com)
sim_num.append(similarlevel)
sim_num, sim_com = (list(x) for x in zip(*sorted(zip(sim_num, sim_com), key=itemgetter(0))))
closestmatch = spicemanip.main(sim_com, 'reverse', "list")
listnumb, relist = 1, []
for item in closestmatch:
if listnumb <= 10:
relist.append(str(item))
listnumb += 1
bot.notice("The following commands may match " + str(querycommand) + ": " + spicemanip.main(relist, 'andlist') + ".", trigger.nick)
return
elif querycommand in commands_list.keys(): triggercommand = triggercommand[:-1]
bot.notice("The following commands match " + str(querycommand) + ": " + str(querycommand) + ".", trigger.nick) if not triggercommand or not len(triggercommand):
return
elif not querycommand:
return
else:
commandlist = []
for command in commands_list.keys():
if command.lower().startswith(querycommand):
commandlist.append(command)
if commandlist == []:
bot.notice("No commands match " + str(querycommand) + ".", trigger.nick)
return 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: else:
bot.notice("The following commands match " + str(querycommand) + ": " + spicemanip.main(commandlist, 'andlist') + ".", trigger.nick) bot.notice("The following commands may match " + str(triggercommand) + ": " + spicemanip.main(closestmatches, 'andlist') + ".", trigger.nick)
return 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)

View File

@ -7,6 +7,7 @@ from __future__ import unicode_literals, absolute_import, division, print_functi
from .CommandsQuery import * from .CommandsQuery import *
from .QueryCommand import * from .QueryCommand import *
from .NickQueryCommand import *
__author__ = 'Sam Zick' __author__ = 'Sam Zick'
__email__ = 'sam@deathbybandaid.net' __email__ = 'sam@deathbybandaid.net'

View File

@ -6,72 +6,114 @@ from __future__ import unicode_literals, absolute_import, print_function, divisi
import sopel.module import sopel.module
from sopel.tools import Identifier from sopel.tools import Identifier
from sopel_modules.SpiceBot_SBTools import bot_logging from sopel_modules.SpiceBot_SBTools import bot_logging
from sopel.db import _deserialize, SopelDB from sopel.db import SopelDB, NickValues, ChannelValues
from sqlalchemy.exc import SQLAlchemyError
import json import json
def setup(bot): def setup(bot):
pass
# Inject Database Functions # Inject Database Functions
bot_logging(bot, 'SpiceBot_Databaseaddons', "Implanting Database functions into bot") bot_logging(bot, 'SpiceBot_Databaseaddons', "Implanting Database functions into bot")
SopelDB.reset_nick_value = SopelDBCache.reset_nick_value SopelDB.delete_nick_value = SopelDBCache.delete_nick_value
SopelDB.adjust_nick_value = SopelDBCache.adjust_nick_value SopelDB.adjust_nick_value = SopelDBCache.adjust_nick_value
SopelDB.reset_channel_value = SopelDBCache.reset_channel_value SopelDB.delete_channel_value = SopelDBCache.delete_channel_value
SopelDB.adjust_channel_value = SopelDBCache.adjust_channel_value SopelDB.adjust_channel_value = SopelDBCache.adjust_channel_value
SopelDB._create_table = SopelDBCache._create_table
class SopelDBCache: class SopelDBCache:
"""Dynamic Table Creation"""
def _create_table(self, tablename):
self.execute('CREATE TABLE IF NOT EXISTS ? (mainid STRING, key STRING, value STRING, PRIMARY KEY (mainid, key))', tablename)
"""Nicks""" """Nicks"""
def reset_nick_value(self, nick, key): def delete_nick_value(self, nick, key):
"""Resets the value for a given key to be associated with the nick.""" """Deletes the value for a given key to be associated with the nick."""
nick = Identifier(nick) nick = Identifier(nick)
nick_id = self.get_nick_id(nick) nick_id = self.get_nick_id(nick)
self.execute('DELETE FROM nick_values WHERE nick_id = ? AND key = ?', [nick_id, key]) 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): def adjust_nick_value(self, nick, key, value):
"""Adjusts the value for a given key to be associated with the nick.""" """Sets the value for a given key to be associated with the nick."""
nick = Identifier(nick) nick = Identifier(nick)
result = self.execute(
'SELECT value FROM nicknames JOIN nick_values '
'ON nicknames.nick_id = nick_values.nick_id '
'WHERE slug = ? AND key = ?',
[nick.lower(), key]
).fetchone()
if result is not None:
result = result[0]
current_value = _deserialize(result)
value = current_value + value
value = json.dumps(value, ensure_ascii=False) value = json.dumps(value, ensure_ascii=False)
nick_id = self.get_nick_id(nick) nick_id = self.get_nick_id(nick)
self.execute('INSERT OR REPLACE INTO nick_values VALUES (?, ?, ?)', session = self.ssession()
[nick_id, key, value]) 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""" """Channels"""
def reset_channel_value(self, channel, key): def delete_channel_value(self, channel, key):
"""Resets the value for a given key to be associated with a channel.""" """Sets the value for a given key to be associated with the channel."""
channel = Identifier(channel).lower() channel = Identifier(channel).lower()
self.execute('DELETE FROM channel_values WHERE channel = ? AND key = ?', [channel, key]) 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): def adjust_channel_value(self, channel, key, value):
"""Adjusts the value for a given key to be associated with the channel.""" """Sets the value for a given key to be associated with the channel."""
channel = Identifier(channel).lower() channel = Identifier(channel).lower()
result = self.execute(
'SELECT value FROM channel_values WHERE channel = ? AND key = ?',
[channel, key]
).fetchone()
if result is not None:
result = result[0]
current_value = _deserialize(result)
value = current_value + value
value = json.dumps(value, ensure_ascii=False) value = json.dumps(value, ensure_ascii=False)
self.execute('INSERT OR REPLACE INTO channel_values VALUES (?, ?, ?)', session = self.ssession()
[channel, key, value]) 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()

View File

@ -6,13 +6,6 @@ from __future__ import unicode_literals, absolute_import, print_function, divisi
import sopel.module import sopel.module
"""Dyanmic Table Creation"""
def db_create_table(bot, tablename):
bot.db._create_table(tablename)
"""Database Direct""" """Database Direct"""
@ -58,7 +51,7 @@ def db_adjust_list(bot, nick, entries, key, adjustmentdirection):
for x in adjustlistnew: for x in adjustlistnew:
if x not in adjustlist: if x not in adjustlist:
adjustlist.append(x) adjustlist.append(x)
if adjustlist == []: if not len(adjustlist):
db_reset_value(bot, nick, key) db_reset_value(bot, nick, key)
else: else:
db_set_nick_value(bot, nick, key, adjustlist) db_set_nick_value(bot, nick, key, adjustlist)

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals, absolute_import, division, print_functi
import sopel.module import sopel.module
from sopel.trigger import PreTrigger from sopel.trigger import PreTrigger
from .System import bot_events_trigger, bot_events_recieved, bot_events_startup_check, bot_events_setup_check from .System import botevents
from sopel_modules.SpiceBot_SBTools import bot_logging from sopel_modules.SpiceBot_SBTools import bot_logging
import time import time
@ -14,59 +14,53 @@ import time
@sopel.module.event('001') @sopel.module.event('001')
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_startup_connection(bot, trigger): def bot_startup_connection(bot, trigger):
bot_events_trigger(bot, 1001, "Welcome to the SpiceBot Events System") botevents.trigger(bot, botevents.BOT_WELCOME, "Welcome to the SpiceBot Events System")
while not len(bot.channels.keys()) > 0: while not len(bot.channels.keys()) > 0:
pass pass
time.sleep(1) time.sleep(1)
bot_events_trigger(bot, 1003, "Bot Connected to IRC") botevents.trigger(bot, botevents.BOT_CONNECTED, "Bot Connected to IRC")
@sopel.module.event('1001') @sopel.module.event(botevents.BOT_WELCOME)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_events_start(bot, trigger): def bot_events_start(bot, trigger):
bot_logging(bot, 'SpiceBot_Events', trigger.args[1], True) bot_logging(bot, 'SpiceBot_Events', trigger.args[1], True)
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)
bot_events_trigger(bot, 1002, "Ready To Process module setup procedures") botevents.trigger(bot, botevents.BOT_READY, "Ready To Process module setup procedures")
while not bot_events_startup_check(bot): while not botevents.startup_check():
pass pass
bot_events_trigger(bot, 1004, "All registered modules setup procedures have completed") botevents.trigger(bot, botevents.BOT_LOADED, "All registered modules setup procedures have completed")
@sopel.module.event('1002') @sopel.module.event(botevents.BOT_READY)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_events_ready(bot, trigger): def bot_events_ready(bot, trigger):
bot_logging(bot, 'SpiceBot_Events', trigger.args[1], True) bot_logging(bot, 'SpiceBot_Events', trigger.args[1], True)
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)
@sopel.module.event('1003') @sopel.module.event(botevents.BOT_CONNECTED)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_events_connected(bot, trigger): def bot_events_connected(bot, trigger):
bot_logging(bot, 'SpiceBot_Events', trigger.args[1], True) bot_logging(bot, 'SpiceBot_Events', trigger.args[1], True)
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)
bot_events_setup_check(bot)
while True: while True:
try: if len(botevents.SpiceBot_Events["trigger_queue"]):
if len(bot.memory['SpiceBot_Events']["queue"]): number = botevents.SpiceBot_Events["trigger_queue"][0]["number"]
number = bot.memory['SpiceBot_Events']["queue"][0]["number"] message = botevents.SpiceBot_Events["trigger_queue"][0]["message"]
message = bot.memory['SpiceBot_Events']["queue"][0]["message"] pretrigger = PreTrigger(
pretrigger = PreTrigger( bot.nick,
bot.nick, ":SpiceBot_Events " + str(number) + " " + str(bot.nick) + " :" + message
":SpiceBot_Events " + str(number) + " " + str(bot.nick) + " :" + message )
) bot.dispatch(pretrigger)
bot.dispatch(pretrigger) del botevents.SpiceBot_Events["trigger_queue"][0]
del bot.memory['SpiceBot_Events']["queue"][0]
except KeyError:
return
@sopel.module.event('1004') @sopel.module.event(botevents.BOT_LOADED)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_events_complete(bot, trigger): def bot_events_complete(bot, trigger):
bot_logging(bot, 'SpiceBot_Events', trigger.args[1], True) bot_logging(bot, 'SpiceBot_Events', trigger.args[1], True)
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)

View File

@ -5,86 +5,93 @@ from __future__ import unicode_literals, absolute_import, print_function, divisi
# sopel imports # sopel imports
import sopel import sopel
from sopel.trigger import PreTrigger from sopel.trigger import PreTrigger
import functools
from sopel_modules.SpiceBot_SBTools import bot_logging from sopel_modules.SpiceBot_SBTools import bot_logging
class BotEvents(object):
"""A dynamic listing of all the notable Bot numeric events.
Events will be assigned a 4-digit number above 1000.
This allows you to do, ``@module.event(botevents.BOT_WELCOME)````
Triggers handled by this module will be processed immediately.
Others will be placed into a queue.
Triggers will be logged by ID and content
"""
def __init__(self):
self.SpiceBot_Events = {
"assigned_IDs": [1000],
"triggers_recieved": {},
"trigger_queue": [],
"startup_required": []
}
def __getattr__(self, name):
''' will only get called for undefined attributes '''
eventnumber = max(self.SpiceBot_Events["assigned_IDs"]) + 1
self.SpiceBot_Events["assigned_IDs"].append(eventnumber)
setattr(self, name, str(eventnumber))
return str(eventnumber)
def trigger(self, bot, number, message="SpiceBot_Events"):
number = str(number)
if number in [self.BOT_WELCOME, self.BOT_READY, self.BOT_CONNECTED, self.BOT_LOADED]:
pretrigger = PreTrigger(
bot.nick,
":SpiceBot_Events " + number + " " + str(bot.nick) + " :" + message
)
bot.dispatch(pretrigger)
else:
pretriggerdict = {"number": number, "message": message}
self.SpiceBot_Events["trigger_queue"].append(pretriggerdict)
def recieved(self, trigger):
eventnumber = str(trigger.event)
message_payload = 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_payload)
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():
return False
return True
def startup_add(self, startlist):
if not isinstance(startlist, list):
startlist = [str(startlist)]
self.SpiceBot_Events["startup_required"].extend(startlist)
def startup_check(self):
for number in self.SpiceBot_Events["startup_required"]:
if str(number) not in self.SpiceBot_Events["triggers_recieved"].keys():
return False
return True
def check_ready(self, checklist):
def actual_decorator(function):
@functools.wraps(function)
def _nop(*args, **kwargs):
# Assign trigger and bot for easy access later
bot, trigger = args[0:2]
while not self.check(checklist):
pass
return function(*args, **kwargs)
return _nop
return actual_decorator
botevents = BotEvents()
def setup(bot): def setup(bot):
bot_logging(bot, 'SpiceBot_Events', "Starting setup procedure") bot_logging(bot, 'SpiceBot_Events', "Starting setup procedure")
bot_events_setup_check(bot) botevents.startup_add([botevents.BOT_WELCOME, botevents.BOT_READY, botevents.BOT_CONNECTED])
bot_events_startup_register(bot, ['1001', '1002', '1003'])
def shutdown(bot):
if "SpiceBot_Events" in bot.memory:
del bot.memory["SpiceBot_Events"]
def bot_events_trigger(bot, number, message):
bot_events_setup_check(bot)
bot.memory["SpiceBot_Events"]["triggers"][str(number)] = message
if str(number) in ['1001', '1002', '1003']:
pretrigger = PreTrigger(
bot.nick,
":SpiceBot_Events " + str(number) + " " + str(bot.nick) + " :" + message
)
bot.dispatch(pretrigger)
else:
pretriggerdict = {"number": number, "message": message}
bot.memory['SpiceBot_Events']["queue"].append(pretriggerdict)
def bot_events_setup_check(bot):
if "SpiceBot_Events" not in bot.memory:
bot.memory["SpiceBot_Events"] = {"triggers": {}, "startup": [], "loaded": [], "queue": []}
def bot_events_check(bot, listreq):
bot_events_setup_check(bot)
if not isinstance(listreq, list):
listreq = [str(listreq)]
for requirement in listreq:
if requirement not in bot.memory["SpiceBot_Events"]["loaded"]:
return False
return True
def bot_events_startup_register(bot, addonreq):
bot_events_setup_check(bot)
if not isinstance(addonreq, list):
addonreq = [str(addonreq)]
bot.memory["SpiceBot_Events"]["startup"].extend(addonreq)
def bot_events_recieved(bot, number):
bot_events_setup_check(bot)
if str(number) not in bot.memory["SpiceBot_Events"]["loaded"]:
bot.memory["SpiceBot_Events"]["loaded"].append(str(number))
def bot_events_startup_check(bot):
bot_events_setup_check(bot)
notcomplete = []
for startupitem in bot.memory["SpiceBot_Events"]["startup"]:
if str(startupitem) not in bot.memory["SpiceBot_Events"]["loaded"]:
notcomplete.append(str(startupitem))
if len(notcomplete):
# bot_logging(bot, 'SpiceBot_Events', str(notcomplete))
return False
else:
return True

View File

@ -7,19 +7,20 @@ from sopel import module
from .gifsearch import getGif from .gifsearch import getGif
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs from sopel_modules.SpiceBot_SBTools import sopel_triggerargs
from sopel_modules.SpiceBot_Events.System import bot_events_check from sopel_modules.SpiceBot_Events.System import botevents
import spicemanip import spicemanip
@botevents.check_ready([botevents.BOT_GIFSEARCH])
@module.commands('gif') @module.commands('gif')
def gif_trigger(bot, trigger): def gif_trigger(bot, trigger):
while not bot_events_check(bot, '2003'): # while not botevents.check(botevents.BOT_GIFSEARCH):
pass # pass
triggerargs, triggercommand = sopel_triggerargs(bot, trigger) triggerargs, triggercommand = sopel_triggerargs(bot, trigger)
if triggerargs == []: if not len(triggerargs):
return bot.osd("Please present a query to search.") return bot.osd("Please present a query to search.")
query = spicemanip.main(triggerargs, 0) query = spicemanip.main(triggerargs, 0)

View File

@ -9,21 +9,22 @@ import sopel.module
import spicemanip import spicemanip
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs from sopel_modules.SpiceBot_SBTools import sopel_triggerargs
from sopel_modules.SpiceBot_Events.System import bot_events_check from sopel_modules.SpiceBot_Events.System import botevents
@botevents.check_ready([botevents.BOT_GIFSEARCH])
@sopel.module.commands('(.*)') @sopel.module.commands('(.*)')
def gifapi_triggers(bot, trigger): def gifapi_triggers(bot, trigger):
while not bot_events_check(bot, '2003'): # while not botevents.check(botevents.BOT_GIFSEARCH):
pass # pass
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'prefix_command') triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'prefix_command')
if triggercommand not in bot.memory["SpiceBot_GifSearch"]['valid_gif_api_dict'].keys(): if triggercommand not in bot.memory["SpiceBot_GifSearch"]['valid_gif_api_dict'].keys():
return return
if triggerargs == []: if not len(triggerargs):
return bot.osd("Please present a query to search.") return bot.osd("Please present a query to search.")
query = spicemanip.main(triggerargs, 0) query = spicemanip.main(triggerargs, 0)

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals, absolute_import, division, print_functi
import sopel.module import sopel.module
from sopel.config.types import StaticSection, ValidatedAttribute from sopel.config.types import StaticSection, ValidatedAttribute
from sopel_modules.SpiceBot_Events.System import bot_events_startup_register, bot_events_recieved, bot_events_trigger from sopel_modules.SpiceBot_Events.System import botevents
from sopel_modules.SpiceBot_CommandsQuery.CommandsQuery import commandsquery_register from sopel_modules.SpiceBot_CommandsQuery.CommandsQuery import commandsquery_register
@ -47,7 +47,7 @@ def configure(config):
def setup(bot): def setup(bot):
bot_logging(bot, 'SpiceBot_GifSearch', "Starting Setup Procedure") bot_logging(bot, 'SpiceBot_GifSearch', "Starting Setup Procedure")
bot_events_startup_register(bot, ['2003']) botevents.startup_add([botevents.BOT_GIFSEARCH])
if 'SpiceBot_GifSearch' not in bot.memory: if 'SpiceBot_GifSearch' not in bot.memory:
bot.memory["SpiceBot_GifSearch"] = {"cache": {}, "badgiflinks": [], 'valid_gif_api_dict': {}} bot.memory["SpiceBot_GifSearch"] = {"cache": {}, "badgiflinks": [], 'valid_gif_api_dict': {}}
@ -79,7 +79,7 @@ def setup(bot):
if validgifapi not in bot.memory["SpiceBot_GifSearch"]['cache'].keys(): if validgifapi not in bot.memory["SpiceBot_GifSearch"]['cache'].keys():
bot.memory["SpiceBot_GifSearch"]['cache'][validgifapi] = dict() bot.memory["SpiceBot_GifSearch"]['cache'][validgifapi] = dict()
bot_events_trigger(bot, 2003, "SpiceBot_GifSearch") botevents.trigger(bot, botevents.BOT_GIFSEARCH, "SpiceBot_GifSearch")
def shutdown(bot): def shutdown(bot):
@ -167,7 +167,7 @@ def getGif(bot, searchdict):
if str(searchdict["searchquery"]) not in bot.memory["SpiceBot_GifSearch"]['cache'][currentapi].keys(): if str(searchdict["searchquery"]) not in bot.memory["SpiceBot_GifSearch"]['cache'][currentapi].keys():
bot.memory["SpiceBot_GifSearch"]['cache'][currentapi][str(searchdict["searchquery"])] = [] bot.memory["SpiceBot_GifSearch"]['cache'][currentapi][str(searchdict["searchquery"])] = []
if bot.memory["SpiceBot_GifSearch"]['cache'][currentapi][str(searchdict["searchquery"])] == []: if not len(bot.memory["SpiceBot_GifSearch"]['cache'][currentapi][str(searchdict["searchquery"])]):
try: try:
page = requests.get(url, headers=header) page = requests.get(url, headers=header)
@ -195,7 +195,7 @@ def getGif(bot, searchdict):
resultsarray.append(cururl) resultsarray.append(cururl)
# make sure there are results # make sure there are results
if resultsarray != []: if len(resultsarray):
# Create Temp dict for every result # Create Temp dict for every result
tempresultnum = 0 tempresultnum = 0
@ -215,10 +215,10 @@ def getGif(bot, searchdict):
verifygoodlinks.append(gifresult) verifygoodlinks.append(gifresult)
bot.memory["SpiceBot_GifSearch"]['cache'][currentapi][str(searchdict["searchquery"])] = verifygoodlinks bot.memory["SpiceBot_GifSearch"]['cache'][currentapi][str(searchdict["searchquery"])] = verifygoodlinks
if bot.memory["SpiceBot_GifSearch"]['cache'][currentapi][str(searchdict["searchquery"])] != []: if len(bot.memory["SpiceBot_GifSearch"]['cache'][currentapi][str(searchdict["searchquery"])]):
gifapiresults.extend(bot.memory["SpiceBot_GifSearch"]['cache'][currentapi][str(searchdict["searchquery"])]) gifapiresults.extend(bot.memory["SpiceBot_GifSearch"]['cache'][currentapi][str(searchdict["searchquery"])])
if gifapiresults == []: if not len(gifapiresults):
return {"error": "No Results were found for '" + searchdict["query"] + "' in the " + str(spicemanip.main(searchdict['gifsearch'], 'orlist')) + " api(s)"} return {"error": "No Results were found for '" + searchdict["query"] + "' in the " + str(spicemanip.main(searchdict['gifsearch'], 'orlist')) + " api(s)"}
random.shuffle(gifapiresults) random.shuffle(gifapiresults)
@ -243,7 +243,7 @@ def getGif(bot, searchdict):
newlist.append(tempdict) newlist.append(tempdict)
gifapiresults = newlist gifapiresults = newlist
if gifapiresults == []: if not len(gifapiresults):
return {"error": "No Results were found for '" + searchdict["query"] + "' in the " + str(spicemanip.main(searchdict['gifsearch'], 'orlist')) + " api(s)"} return {"error": "No Results were found for '" + searchdict["query"] + "' in the " + str(spicemanip.main(searchdict['gifsearch'], 'orlist')) + " api(s)"}
# return dict # return dict
@ -251,7 +251,7 @@ def getGif(bot, searchdict):
return gifdict return gifdict
@sopel.module.event('2003') @sopel.module.event(botevents.BOT_GIFSEARCH)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_events_setup(bot, trigger): def bot_events_setup(bot, trigger):
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals, absolute_import, division, print_functi
import sopel.module import sopel.module
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs from sopel_modules.SpiceBot_SBTools import sopel_triggerargs
from sopel_modules.SpiceBot_Events.System import bot_events_check, bot_events_recieved from sopel_modules.SpiceBot_Events.System import botevents
def setup(bot): def setup(bot):
@ -18,21 +18,22 @@ def shutdown(bot):
del bot.memory["SpiceBot_InvalidCommand"] del bot.memory["SpiceBot_InvalidCommand"]
@sopel.module.event('1004') @sopel.module.event(botevents.BOT_LOADED)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_events_complete(bot, trigger): def bot_events_complete(bot, trigger):
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)
for comtype in bot.memory['SpiceBot_CommandsQuery']['commands'].keys(): for comtype in bot.memory['SpiceBot_CommandsQuery']['commands'].keys():
bot.memory["SpiceBot_InvalidCommand"]["valid"].extend(bot.memory['SpiceBot_CommandsQuery']['commands'][comtype].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('(.*)') @sopel.module.commands('(.*)')
def InvalidCommand_triggers(bot, trigger): def InvalidCommand_triggers(bot, trigger):
return return
while not bot_events_check(bot, ['1004', '2002']): # while not botevents.check([botevents.BOT_LOADED, botevents.BOT_COMMANDSQUERY]):
pass # pass
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'prefix_command') triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'prefix_command')

View File

@ -12,7 +12,6 @@ from __future__ import unicode_literals, absolute_import, division, print_functi
import sopel.bot import sopel.bot
from sopel import tools, module from sopel import tools, module
from sopel.tools import Identifier from sopel.tools import Identifier
from sopel.module import HALFOP
from sopel.config.types import StaticSection, ValidatedAttribute from sopel.config.types import StaticSection, ValidatedAttribute
from sopel_modules.SpiceBot_SBTools import bot_logging from sopel_modules.SpiceBot_SBTools import bot_logging
@ -28,8 +27,8 @@ __version__ = '0.1.2'
def configure(config): def configure(config):
config.define_section("MAXTARGCONFIG_KICK", MAXTARGCONFIG_KICK, validate=False) config.define_section("SpiceBot_Kick", SpiceBot_Kick, validate=False)
config.MAXTARGCONFIG_KICK.configure_setting('kick', 'MAXTARG limit for KICK') config.SpiceBot_Kick.configure_setting('kick', 'MAXTARG limit for KICK')
def setup(bot): def setup(bot):
@ -41,7 +40,7 @@ def setup(bot):
# verify config settings for server # verify config settings for server
bot_logging(bot, 'SpiceBot_Kick', "Checking for config settings") bot_logging(bot, 'SpiceBot_Kick', "Checking for config settings")
bot.config.define_section("MAXTARGCONFIG_KICK", MAXTARGCONFIG_KICK, validate=False) bot.config.define_section("SpiceBot_Kick", SpiceBot_Kick, validate=False)
@module.event('005') @module.event('005')
@ -63,10 +62,10 @@ def parse_event_005(bot, trigger):
except IndexError: except IndexError:
value = None value = None
if value: if value:
bot.config.MAXTARGCONFIG_KICK.kick = int(value) bot.config.SpiceBot_Kick.kick = int(value)
class MAXTARGCONFIG_KICK(StaticSection): class SpiceBot_Kick(StaticSection):
kick = ValidatedAttribute('kick', default=1) kick = ValidatedAttribute('kick', default=1)
@ -80,8 +79,7 @@ class SopelKICK:
The bot must be a channel operator in specified channel for this to work. The bot must be a channel operator in specified channel for this to work.
.. versionadded:: 7.0 .. versionadded:: 7.0
""" """
if self.channels[channel].privileges[self.nick] < HALFOP: self.write(['KICK', channel, nick], text)
self.write(['KICK', channel, nick], text)
class SopelWrapperKICK(object): class SopelWrapperKICK(object):
@ -89,9 +87,9 @@ class SopelWrapperKICK(object):
def kick(self, nick, channel=None, message=None): def kick(self, nick, channel=None, message=None):
if channel is None: if channel is None:
if self._trigger.is_privmsg: if self._trigger.is_privmsg:
return raise RuntimeError('Error: KICK requires a channel.')
else: else:
channel = self._trigger.sender channel = self._trigger.sender
if nick is None: if nick is None:
return raise RuntimeError('Error: KICK requires a nick.')
self._bot.kick(nick, channel, message) self._bot.kick(nick, channel, message)

View File

@ -4,27 +4,28 @@ from __future__ import unicode_literals, absolute_import, division, print_functi
import sopel.module import sopel.module
from sopel_modules.SpiceBot_Events.System import bot_events_recieved from sopel_modules.SpiceBot_Events.System import botevents
from sopel_modules.SpiceBot_SBTools import bot_logging
from .Logs import stdio_logs_fetch from .Logs import stdio_logs_fetch
@sopel.module.event('2005') @sopel.module.event(botevents.BOT_STARTUPMONOLOGUE)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_startup_monologue_start(bot, trigger): def bot_startup_monologue_start(bot, trigger):
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)
debuglines = stdio_logs_fetch(bot) debuglines = stdio_logs_fetch(bot)
searchphrasefound = [] searchphrasefound = []
for line in debuglines: for line in debuglines:
if "modules failed to load" in str(line) and "0 modules failed to load" not in str(line): if str(line).endswith("failed to load") and not str(line).startswith("0"):
searchphrase = str(line).replace(" modules failed to load", "") searchphrasefound.append(line)
searchphrasefound.append(str(searchphrase) + " module(s) failed")
elif "dict files failed to load" in str(line) and "0 dict files failed to load" not in str(line):
searchphrase = str(line).replace(" dict files failed to load", "")
searchphrasefound.append(str(searchphrase) + " dict file(s) failed")
if len(searchphrasefound): if len(searchphrasefound):
for foundphase in searchphrasefound:
bot_logging(bot, 'SpiceBot_Logs', str(foundphase))
searchphrasefound.insert(0, "Notice to Bot Admins: ") searchphrasefound.insert(0, "Notice to Bot Admins: ")
searchphrasefound.append("Run the debug command for more information.") searchphrasefound.append("Run the debug command for more information.")
bot.osd(searchphrasefound, bot.channels.keys()) bot.osd(searchphrasefound, bot.channels.keys())
else:
bot_logging(bot, 'SpiceBot_Logs', "No issues found at bot startup!", True)

View File

@ -6,7 +6,7 @@ import sopel.module
from sopel.config.types import StaticSection, ValidatedAttribute from sopel.config.types import StaticSection, ValidatedAttribute
from sopel_modules.SpiceBot_SBTools import bot_logging from sopel_modules.SpiceBot_SBTools import bot_logging
from sopel_modules.SpiceBot_Events.System import bot_events_startup_register, bot_events_recieved, bot_events_trigger from sopel_modules.SpiceBot_Events.System import botevents
import os import os
@ -26,11 +26,11 @@ def setup(bot):
bot_logging(bot, 'SpiceBot_Logs', "Starting Setup Procedure") bot_logging(bot, 'SpiceBot_Logs', "Starting Setup Procedure")
bot.config.define_section("SpiceBot_Logs", SpiceBot_Logs_MainSection, validate=False) bot.config.define_section("SpiceBot_Logs", SpiceBot_Logs_MainSection, validate=False)
bot_events_startup_register(bot, ['2004']) botevents.startup_add([botevents.BOT_LOGS])
bot_logs_setup_check(bot) bot_logs_setup_check(bot)
bot_events_trigger(bot, 2004, "SpiceBot_Logs") botevents.trigger(bot, botevents.BOT_LOGS, "SpiceBot_Logs")
def bot_logs_setup_check(bot): def bot_logs_setup_check(bot):
@ -43,10 +43,10 @@ def shutdown(bot):
del bot.memory["SpiceBot_Logs"] del bot.memory["SpiceBot_Logs"]
@sopel.module.event('1003') @sopel.module.event(botevents.BOT_CONNECTED)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def join_log_channel(bot, trigger): def join_log_channel(bot, trigger):
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)
if bot.config.SpiceBot_Logs.logging_channel: if bot.config.SpiceBot_Logs.logging_channel:
channel = bot.config.SpiceBot_Logs.logging_channel channel = bot.config.SpiceBot_Logs.logging_channel
@ -68,7 +68,7 @@ def join_log_channel(bot, trigger):
def stdio_logs_fetch(bot): def stdio_logs_fetch(bot):
stdio_ignore = ["Loaded:"] stdio_ignore = []
for logtype in bot.memory['SpiceBot_Logs']["logs"].keys(): for logtype in bot.memory['SpiceBot_Logs']["logs"].keys():
stdio_ignore.append("[" + logtype + "]") stdio_ignore.append("[" + logtype + "]")
@ -94,10 +94,15 @@ def stdio_logs_fetch(bot):
filelines = [] filelines = []
debuglines = [] debuglines = []
loadedmodules = []
for line in filelines: for line in filelines:
if not line.startswith(tuple(stdio_ignore)): if line.startswith("Loaded:"):
if not line.isspace(): loadedmodules.append(str(line).split("Loaded:")[-1])
else:
if not line.startswith(tuple(stdio_ignore)) and not line.isspace():
debuglines.append(str(line)) debuglines.append(str(line))
loadedmodules = "Loaded: " + spicemanip.main(loadedmodules, 'andlist')
debuglines.insert(1, loadedmodules)
return debuglines return debuglines
@ -126,7 +131,7 @@ def get_running_pid(bot):
return pidnum return pidnum
@sopel.module.event('2004') @sopel.module.event(botevents.BOT_LOGS)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_events_setup(bot, trigger): def bot_events_setup(bot, trigger):
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)

View File

@ -6,16 +6,17 @@ import sopel.module
import spicemanip import spicemanip
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, command_permissions_check, inlist, inlist_match from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, command_permissions_check, inlist, inlist_match, similar_list
from sopel_modules.SpiceBot_Events.System import bot_events_check from sopel_modules.SpiceBot_Events.System import botevents
from .Logs import systemd_logs_fetch, stdio_logs_fetch from .Logs import systemd_logs_fetch, stdio_logs_fetch
@botevents.check_ready([botevents.BOT_LOGS])
@sopel.module.nickname_commands('logs', 'debug') @sopel.module.nickname_commands('logs', 'debug')
def bot_command_logs(bot, trigger): def bot_command_logs(bot, trigger):
while not bot_events_check(bot, '2004'): # while not botevents.check(botevents.BOT_LOGS):
pass # pass
if not command_permissions_check(bot, trigger, ['admins', 'owner', 'OP', 'ADMIN', 'OWNER']): 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.") bot.say("I was unable to process this Bot Nick command due to privilege issues.")
@ -24,10 +25,19 @@ def bot_command_logs(bot, trigger):
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'nickname_command') triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'nickname_command')
logtype = spicemanip.main(triggerargs, 1) or None logtype = spicemanip.main(triggerargs, 1) or None
if not logtype or not inlist(bot, logtype, bot.memory['SpiceBot_Logs']["logs"].keys()): if not logtype:
bot.osd("Current valid log(s) include: " + spicemanip.main(bot.memory['SpiceBot_Logs']["logs"].keys(), 'andlist'), trigger.sender, 'action') bot.osd("Current valid log(s) include: " + spicemanip.main(bot.memory['SpiceBot_Logs']["logs"].keys(), 'andlist'), trigger.sender, 'action')
return return
if not inlist(bot, logtype, bot.memory['SpiceBot_Logs']["logs"].keys()):
closestmatches = similar_list(bot, logtype, bot.memory['SpiceBot_Logs']["logs"].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, bot.memory['SpiceBot_Logs']["logs"].keys()) logtype = inlist_match(bot, logtype, bot.memory['SpiceBot_Logs']["logs"].keys())
if logtype == "Sopel_systemd": if logtype == "Sopel_systemd":

View File

@ -84,7 +84,7 @@ def command_permissions_check(bot, trigger, privslist):
else: else:
commandrunconsensus.append('True') commandrunconsensus.append('True')
if privslist == []: if not len(privslist):
commandrunconsensus.append('True') commandrunconsensus.append('True')
if 'True' not in commandrunconsensus: if 'True' not in commandrunconsensus:
@ -236,13 +236,13 @@ def similar_list(bot, searchitem, searchlist, matchcount=1, searchorder='reverse
sim_listitems, sim_num = [], [] sim_listitems, sim_num = [], []
for listitem in searchlist: for listitem in searchlist:
similarlevel = similar(searchitem.lower(), listitem.lower()) similarlevel = SequenceMatcher(None, searchitem.lower(), listitem.lower()).ratio()
if similarlevel >= .75: if similarlevel >= .75:
sim_listitems.append(listitem) sim_listitems.append(listitem)
sim_num.append(similarlevel) sim_num.append(similarlevel)
if len(sim_listitems) and len(sim_num): if len(sim_listitems) and len(sim_num):
sim_num, sim_listitems = array_arrangesort(bot, sim_num, sim_listitems) sim_num, sim_listitems = (list(x) for x in zip(*sorted(zip(sim_num, sim_listitems), key=itemgetter(0))))
if searchorder == 'reverse': if searchorder == 'reverse':
sim_listitems = spicemanip.main(sim_listitems, 'reverse', "list") sim_listitems = spicemanip.main(sim_listitems, 'reverse', "list")
@ -257,6 +257,13 @@ def array_arrangesort(bot, sortbyarray, arrayb):
return sortbyarray, arrayb return sortbyarray, arrayb
def letters_in_string(text):
if text.isupper() or text.islower():
return True
else:
return False
"""Channel Functions""" """Channel Functions"""
@ -433,10 +440,10 @@ def read_directory_json_to_dict(bot, directories, configtypename="Config File",
if filecount: if filecount:
if bot: if bot:
bot_logging(bot, log_from, 'Registered %d %s files,' % (filecount, configtypename)) bot_logging(bot, log_from, 'Registered %d %s dict files,' % (filecount, configtypename))
bot_logging(bot, log_from, '%d %s files failed to load' % (fileopenfail, configtypename)) bot_logging(bot, log_from, '%d %s dict files failed to load' % (fileopenfail, configtypename), True)
else: else:
if bot: if bot:
bot_logging(bot, log_from, "Warning: Couldn't load any %s files" % (configtypename)) bot_logging(bot, log_from, "Warning: Couldn't load any %s dict files" % (configtypename))
return configs_dict return configs_dict

View File

@ -4,19 +4,19 @@ from __future__ import unicode_literals, absolute_import, division, print_functi
import sopel.module import sopel.module
from sopel_modules.SpiceBot_Events.System import bot_events_recieved, bot_events_startup_register from sopel_modules.SpiceBot_Events.System import botevents
from sopel_modules.SpiceBot_SBTools import bot_logging from sopel_modules.SpiceBot_SBTools import bot_logging
def setup(bot): def setup(bot):
bot_logging(bot, 'SpiceBot_StartupMonologue', "Starting setup procedure") bot_logging(bot, 'SpiceBot_StartupMonologue', "Starting setup procedure")
bot_events_startup_register(bot, ['2010', '2011', '2012']) botevents.startup_add([botevents.BOT_STARTUPMONOLOGUE_CHANNELS, botevents.BOT_STARTUPMONOLOGUE_COMMANDSQUERY, botevents.BOT_STARTUPMONOLOGUE_CONNECTED])
if 'SpiceBot_StartupMonologue' not in bot.memory: if 'SpiceBot_StartupMonologue' not in bot.memory:
bot.memory['SpiceBot_StartupMonologue'] = [] bot.memory['SpiceBot_StartupMonologue'] = []
@sopel.module.event('2005', '2010', '2011', '2012') @sopel.module.event(botevents.BOT_STARTUPMONOLOGUE, botevents.BOT_STARTUPMONOLOGUE_CHANNELS, botevents.BOT_STARTUPMONOLOGUE_COMMANDSQUERY, botevents.BOT_STARTUPMONOLOGUE_CONNECTED)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_events_setup(bot, trigger): def bot_events_setup(bot, trigger):
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)

View File

@ -4,27 +4,28 @@ from __future__ import unicode_literals, absolute_import, division, print_functi
import sopel.module import sopel.module
from sopel_modules.SpiceBot_Events.System import bot_events_recieved, bot_events_trigger from sopel_modules.SpiceBot_Events.System import botevents
from sopel_modules.SpiceBot_SBTools import humanized_time, bot_logging from sopel_modules.SpiceBot_SBTools import humanized_time, bot_logging
import time import time
@sopel.module.event('1003') @sopel.module.event(botevents.BOT_CONNECTED)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_startup_monologue_start(bot, trigger): def bot_startup_monologue_start(bot, trigger):
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)
# Startup # Startup
bot_logging(bot, 'SpiceBot_StartupMonologue', bot.nick + " is now starting. Please wait while I load my configuration") bot_logging(bot, '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') bot.osd(" is now starting. Please wait while I load my configuration.", bot.channels.keys(), 'ACTION')
bot_events_trigger(bot, 2012, "SpiceBot_StartupMonologue") botevents.trigger(bot, botevents.BOT_STARTUPMONOLOGUE_CONNECTED, "SpiceBot_StartupMonologue")
@sopel.module.event('2002') @sopel.module.event(botevents.BOT_COMMANDSQUERY)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_startup_monologue_commands(bot, trigger): def bot_startup_monologue_commands(bot, trigger):
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)
availablecomsnum, availablecomsfiles = 0, 0 availablecomsnum, availablecomsfiles = 0, 0
for commandstype in bot.memory['SpiceBot_CommandsQuery']['commands'].keys(): for commandstype in bot.memory['SpiceBot_CommandsQuery']['commands'].keys():
@ -34,25 +35,25 @@ def bot_startup_monologue_commands(bot, trigger):
bot.memory['SpiceBot_StartupMonologue'].append("There are " + str(availablecomsnum) + " commands available in " + str(availablecomsfiles) + " files.") bot.memory['SpiceBot_StartupMonologue'].append("There are " + str(availablecomsnum) + " commands available in " + str(availablecomsfiles) + " files.")
bot_logging(bot, 'SpiceBot_StartupMonologue', "There are " + str(availablecomsnum) + " commands available in " + str(availablecomsfiles) + " files.") bot_logging(bot, 'SpiceBot_StartupMonologue', "There are " + str(availablecomsnum) + " commands available in " + str(availablecomsfiles) + " files.")
bot_events_trigger(bot, 2011, "SpiceBot_StartupMonologue") botevents.trigger(bot, botevents.BOT_STARTUPMONOLOGUE_COMMANDSQUERY, "SpiceBot_StartupMonologue")
@sopel.module.event('2001') @sopel.module.event(botevents.BOT_CHANNELS)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_startup_monologue_channels(bot, trigger): def bot_startup_monologue_channels(bot, trigger):
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)
botcount = len(bot.channels.keys()) botcount = len(bot.channels.keys())
servercount = len(bot.memory['SpiceBot_Channels']['channels'].keys()) servercount = len(bot.memory['SpiceBot_Channels']['channels'].keys())
bot.memory['SpiceBot_StartupMonologue'].append("I am in " + str(botcount) + " of " + str(servercount) + " channel(s) available on this server.") bot.memory['SpiceBot_StartupMonologue'].append("I am in " + str(botcount) + " of " + str(servercount) + " channel(s) available on this server.")
bot_events_trigger(bot, 2010, "SpiceBot_StartupMonologue") botevents.trigger(bot, botevents.BOT_STARTUPMONOLOGUE_CHANNELS, "SpiceBot_StartupMonologue")
@sopel.module.event('1004') @sopel.module.event(botevents.BOT_LOADED)
@sopel.module.rule('.*') @sopel.module.rule('.*')
def bot_startup_monologue_display(bot, trigger): def bot_startup_monologue_display(bot, trigger):
bot_events_recieved(bot, trigger.event) botevents.recieved(trigger)
timesince = humanized_time(time.time() - bot.memory["SpiceBot_Uptime"]) timesince = humanized_time(time.time() - bot.memory["SpiceBot_Uptime"])
bot.memory['SpiceBot_StartupMonologue'].append("Startup took " + timesince) bot.memory['SpiceBot_StartupMonologue'].append("Startup took " + timesince)
@ -63,4 +64,5 @@ def bot_startup_monologue_display(bot, trigger):
bot.osd(bot.memory['SpiceBot_StartupMonologue'], bot.channels.keys(), 'ACTION') bot.osd(bot.memory['SpiceBot_StartupMonologue'], bot.channels.keys(), 'ACTION')
bot_events_trigger(bot, 2005, "SpiceBot_StartupMonologue") botevents.trigger(bot, botevents.BOT_STARTUPMONOLOGUE, "SpiceBot_StartupMonologue")
bot_logging(bot, 'SpiceBot_StartupMonologue', "Startup Monologue has been issued to all channels.", True)

View File

@ -27,9 +27,13 @@ __version__ = '0.1.2'
def configure(config): def configure(config):
config.define_section("MAXTARGCONFIG", MAXTARGCONFIG, validate=False) config.define_section("SpiceBot_OSD", SpiceBot_OSD, validate=False)
config.MAXTARGCONFIG.configure_setting('notice', 'MAXTARG limit for NOTICE') config.SpiceBot_OSD.configure_setting('notice', 'MAXTARG limit for NOTICE')
config.MAXTARGCONFIG.configure_setting('privmsg', 'MAXTARG limit for PRIVMSG') 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): def setup(bot):
@ -57,7 +61,7 @@ def setup(bot):
# verify config settings for server # verify config settings for server
bot_logging(bot, 'SpiceBot_OSD', "Checking for config settings") bot_logging(bot, 'SpiceBot_OSD', "Checking for config settings")
bot.config.define_section("MAXTARGCONFIG", MAXTARGCONFIG, validate=False) bot.config.define_section("SpiceBot_OSD", SpiceBot_OSD, validate=False)
@module.event('005') @module.event('005')
@ -80,15 +84,29 @@ def parse_event_005(bot, trigger):
value = None value = None
if value: if value:
if settingname.upper() == 'NOTICE': if settingname.upper() == 'NOTICE':
bot.config.MAXTARGCONFIG.notice = int(value) bot.config.SpiceBot_OSD.notice = int(value)
elif settingname.upper() == 'PRIVMSG': elif settingname.upper() == 'PRIVMSG':
bot.config.MAXTARGCONFIG.privmsg = int(value) bot.config.SpiceBot_OSD.privmsg = int(value)
class MAXTARGCONFIG(StaticSection): class SpiceBot_OSD(StaticSection):
"""MAXTARG"""
notice = ValidatedAttribute('notice', default=1) notice = ValidatedAttribute('notice', default=1)
privmsg = ValidatedAttribute('privmsg', default=1) privmsg = ValidatedAttribute('privmsg', default=1)
flood_burst_lines = ValidatedAttribute('flood_burst_lines', int, default=4)
"""How many messages can be sent in burst mode."""
flood_empty_wait = ValidatedAttribute('flood_empty_wait', float, default=0.7)
"""How long to wait between sending messages when not in burst mode, in seconds."""
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."""
class ToolsOSD: class ToolsOSD:
@ -117,9 +135,9 @@ class ToolsOSD:
raise ValueError("Recipients list empty.") raise ValueError("Recipients list empty.")
if text_method == 'NOTICE': if text_method == 'NOTICE':
maxtargets = bot.config.MAXTARGCONFIG.notice maxtargets = bot.config.SpiceBot_OSD.notice
elif text_method in ['PRIVMSG', 'ACTION']: elif text_method in ['PRIVMSG', 'ACTION']:
maxtargets = bot.config.MAXTARGCONFIG.privmsg maxtargets = bot.config.SpiceBot_OSD.privmsg
maxtargets = int(maxtargets) maxtargets = int(maxtargets)
recipientgroups = [] recipientgroups = []
@ -259,17 +277,12 @@ class SopelOSD:
for recipientgroup in recipientgroups: for recipientgroup in recipientgroups:
text_method = text_method_orig text_method = text_method_orig
# No messages within the last 3 seconds? Go ahead!
# Otherwise, wait so it's been at least 0.8 seconds + penalty
recipient_id = Identifier(recipientgroup) recipient_id = Identifier(recipientgroup)
recipient_stack = self.stack.setdefault(recipient_id, { recipient_stack = self.stack.setdefault(recipient_id, {
'messages': [], 'messages': [],
'flood_left': 4, 'flood_left': self.config.SpiceBot_OSD.flood_burst_lines,
'dots': 0, 'dots': 0,
# TODO
# 'flood_left': self.config.core.flood_burst_lines,
}) })
recipient_stack['dots'] = 0 recipient_stack['dots'] = 0
@ -281,32 +294,30 @@ class SopelOSD:
if not recipient_stack['flood_left']: if not recipient_stack['flood_left']:
elapsed = time.time() - recipient_stack['messages'][-1][0] elapsed = time.time() - recipient_stack['messages'][-1][0]
# TODO recipient_stack['flood_left'] = min(
# recipient_stack['flood_left'] = min( self.config.SpiceBot_OSD.flood_burst_lines,
# self.config.core.flood_burst_lines, int(elapsed) * self.config.SpiceBot_OSD.flood_refill_rate)
# int(elapsed) * self.config.core.flood_refill_rate)
recipient_stack['flood_left'] = min(4, int(elapsed) * 1)
if not recipient_stack['flood_left']: if not recipient_stack['flood_left']:
elapsed = time.time() - recipient_stack['messages'][-1][0] elapsed = time.time() - recipient_stack['messages'][-1][0]
penalty = float(max(0, len(text) - 50)) / 70 penalty = float(max(0, len(text) - 50)) / 70
# Never wait more than 2 seconds # Never wait more than 2 seconds
# wait = min(self.config.core.flood_empty_wait + penalty, 2) # TODO wait = min(self.config.SpiceBot_OSD.flood_empty_wait + penalty, 2)
wait = min(0.7 + penalty, 2)
if elapsed < wait: if elapsed < wait:
time.sleep(wait - elapsed) time.sleep(wait - elapsed)
# Loop detection # Loop detection
messages = [m[1] for m in recipient_stack['messages'][-8:]] messages = [m[1] for m in recipient_stack['messages'][-8:]]
# If what we about to send repeated at least 5 times in the if self.config.SpiceBot_OSD.flood_dots:
# last 2 minutes, replace with '...' # If what we about to send repeated at least 5 times in the
if messages.count(text) >= 5 and elapsed < 120: # last 2 minutes, replace with '...'
recipient_stack['dots'] += 1 if messages.count(text) >= 5 and elapsed < 120:
else: recipient_stack['dots'] += 1
recipient_stack['dots'] = 0 else:
recipient_stack['dots'] = 0
if not recipient_stack['dots'] >= 3: if recipient_stack['dots'] <= 3:
recipient_stack['flood_left'] = max(0, recipient_stack['flood_left'] - 1) recipient_stack['flood_left'] = max(0, recipient_stack['flood_left'] - 1)
recipient_stack['messages'].append((time.time(), self.safe(text))) recipient_stack['messages'].append((time.time(), self.safe(text)))
@ -377,7 +388,10 @@ class SopelOSD:
self.osd(text, dest, 'PRIVMSG', max_messages) self.osd(text, dest, 'PRIVMSG', max_messages)
def msg(self, recipient, text, max_messages=1): def msg(self, recipient, text, max_messages=1):
# Deprecated, but way too much of a pain to remove. """
.. deprecated:: 6.0
Use :meth:`say` instead. Will be removed in Sopel 8.
"""
self.osd(text, recipient, 'PRIVMSG', max_messages) self.osd(text, recipient, 'PRIVMSG', max_messages)
@ -392,19 +406,16 @@ class SopelWrapperOSD(object):
if destination is None: if destination is None:
destination = self._trigger.sender destination = self._trigger.sender
self._bot.osd(self, message, destination, 'PRIVMSG', 1) self._bot.osd(self, message, destination, 'PRIVMSG', 1)
# self._bot.say(message, destination, max_messages)
def action(self, message, destination=None, max_messages=1): def action(self, message, destination=None, max_messages=1):
if destination is None: if destination is None:
destination = self._trigger.sender destination = self._trigger.sender
self._bot.osd(self, message, destination, 'ACTION', 1) self._bot.osd(self, message, destination, 'ACTION', 1)
# self._bot.action(message, destination, max_messages)
def notice(self, message, destination=None, max_messages=1): def notice(self, message, destination=None, max_messages=1):
if destination is None: if destination is None:
destination = self._trigger.sender destination = self._trigger.sender
self._bot.osd(self, message, destination, 'NOTICE', 1) self._bot.osd(self, message, destination, 'NOTICE', 1)
# self._bot.notice(message, destination, max_messages)
def reply(self, message, destination=None, reply_to=None, notice=False, max_messages=1): def reply(self, message, destination=None, reply_to=None, notice=False, max_messages=1):
if destination is None: if destination is None:
@ -416,4 +427,3 @@ class SopelWrapperOSD(object):
self._bot.osd(self, message, destination, 'NOTICE', 1) self._bot.osd(self, message, destination, 'NOTICE', 1)
else: else:
self._bot.osd(self, message, destination, 'PRIVMSG', 1) self._bot.osd(self, message, destination, 'PRIVMSG', 1)
# self._bot.reply(message, destination, reply_to, notice, max_messages)