Merge pull request #13 from deathbybandaid/development

Development
This commit is contained in:
Deathbybandaid 2019-05-03 13:23:08 -04:00 committed by GitHub
commit 81dd6f6aed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 555 additions and 122 deletions

View File

@ -1,5 +1,4 @@
sopel>=6.0,<7
spicemanip>=0.1.6
gitpython
sopel-modules.osd
fake-useragent

View File

@ -27,7 +27,7 @@ with open('dev-requirements.txt') as dev_requirements_file:
setup(
name='sopel_modules.SpiceBot',
version='0.1.0',
version='0.1.1',
description='SpiceBot aims to run SpiceBot as an IRC service',
long_description=readme + '\n\n' + history,
author='Sam Zick',

View File

@ -0,0 +1,37 @@
# coding=utf-8
from __future__ import unicode_literals, absolute_import, division, print_function
import sopel.module
import spicemanip
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, bot_privs
def configure(config):
pass
def setup(bot):
pass
@sopel.module.nickname_commands('owners', 'owner')
def bot_command_owners(bot, trigger):
bot_command_process(bot, trigger)
@sopel.module.nickname_commands('admins')
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'
privlist = spicemanip.main(bot_privs(bot, triggercommand), 'andlist')
bot.osd(str(bot.nick) + " " + triggercommand + ": " + privlist)

View File

@ -0,0 +1,8 @@
# coding=utf8
from __future__ import unicode_literals, absolute_import, division, print_function
from .BotPrivs import *
__author__ = 'Sam Zick'
__email__ = 'sam@deathbybandaid.net'
__version__ = '0.1.1'

View File

@ -12,4 +12,4 @@ from .Startup_Complete import *
__author__ = 'Sam Zick'
__email__ = 'sam@deathbybandaid.net'
__version__ = '0.1.0'
__version__ = '0.1.1'

View File

@ -11,8 +11,6 @@ import time
import spicemanip
import sopel_modules.osd
from sopel_modules.SpiceBot_SBTools import (
sopel_triggerargs, inlist, topic_compile, channel_privs,
join_all_channels, chanadmin_all_channels, channel_list_current
@ -126,7 +124,8 @@ def watch_chanlist_complete(bot, trigger):
@sopel.module.nickname_commands('channels', 'channel')
def nickname_comand_chanstats(bot, trigger):
triggerargs = sopel_triggerargs(bot, trigger, 'nickname_command')
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'nickname_command')
if not len(triggerargs):
commandused = 'list'
@ -185,91 +184,22 @@ def nickname_comand_chanstats(bot, trigger):
bot.osd("Topic for {}: {}".format(channel, topic))
return
# OP list
if commandused == 'op':
channel = spicemanip.main(triggerargs, 1)
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
bot.osd("Channel name {} not valid.".format(channel))
return
if not inlist(bot, 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())
dispmsg = []
if not len(privlist):
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
if commandused.upper() in ['OP', 'HOP', 'VOICE', 'OWNER', 'ADMIN']:
if not len(triggerargs):
if trigger.is_privmsg:
bot.osd("Channel name required.")
return
else:
channel = trigger.sender
else:
oplist = spicemanip.main(privlist, 'andlist')
dispmsg.append("Channel " + commandused.upper() + "s for " + str(channel) + " are: " + oplist)
bot.osd(dispmsg, trigger.nick, 'notice')
return
channel = spicemanip.main(triggerargs, 1)
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
bot.osd("Channel name {} not valid.".format(channel))
return
if not inlist(bot, channel.lower(), bot.channels.keys()):
bot.osd("I need to be in {} to see nick privileges.".format(channel))
return
# HOP list
if commandused == 'hop':
channel = spicemanip.main(triggerargs, 1)
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
bot.osd("Channel name {} not valid.".format(channel))
return
if not inlist(bot, 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())
dispmsg = []
if not len(privlist):
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
else:
oplist = spicemanip.main(privlist, 'andlist')
dispmsg.append("Channel " + commandused.upper() + "s for " + str(channel) + " are: " + oplist)
bot.osd(dispmsg, trigger.nick, 'notice')
return
# Voice List
if commandused == 'voice':
channel = spicemanip.main(triggerargs, 1)
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
bot.osd("Channel name {} not valid.".format(channel))
return
if not inlist(bot, 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())
dispmsg = []
if not len(privlist):
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
else:
oplist = spicemanip.main(privlist, 'andlist')
dispmsg.append("Channel " + commandused.upper() + "s for " + str(channel) + " are: " + oplist)
bot.osd(dispmsg, trigger.nick, 'notice')
return
# owner List
if commandused == 'owner':
channel = spicemanip.main(triggerargs, 1)
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
bot.osd("Channel name {} not valid.".format(channel))
return
if not inlist(bot, 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())
dispmsg = []
if not len(privlist):
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
else:
oplist = spicemanip.main(privlist, 'andlist')
dispmsg.append("Channel " + commandused.upper() + "s for " + str(channel) + " are: " + oplist)
bot.osd(dispmsg, trigger.nick, 'notice')
return
# admin List
if commandused == 'admin':
channel = spicemanip.main(triggerargs, 1)
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
bot.osd("Channel name {} not valid.".format(channel))
return
if not inlist(bot, 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())
dispmsg = []
if not len(privlist):

View File

@ -9,4 +9,4 @@ from .CommandsQuery import *
__author__ = 'Sam Zick'
__email__ = 'sam@deathbybandaid.net'
__version__ = '0.1.0'
__version__ = '0.1.1'

View File

@ -11,4 +11,4 @@ from .gifsearch import *
__author__ = 'Sam Zick'
__email__ = 'sam@deathbybandaid.net'
__version__ = '0.1.0'
__version__ = '0.1.1'

View File

@ -6,8 +6,6 @@ from sopel import module
from .gifsearch import getGif
import sopel_modules.osd
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs
import spicemanip
@ -19,7 +17,7 @@ def gif_trigger(bot, trigger):
while "SpiceBot_GifSearch" not in bot.memory:
pass
triggerargs = sopel_triggerargs(bot, trigger)
triggerargs, triggercommand = sopel_triggerargs(bot, trigger)
if triggerargs == []:
return bot.osd("Please present a query to search.")

View File

@ -6,8 +6,6 @@ from .gifsearch import getGif
import sopel.module
import sopel_modules.osd
import spicemanip
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs
@ -19,16 +17,16 @@ def gifapi_triggers(bot, trigger):
while "SpiceBot_GifSearch" not in bot.memory:
pass
triggerargs, prefixcommand = sopel_triggerargs(bot, trigger, 'prefix_command')
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'prefix_command')
if prefixcommand 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
if triggerargs == []:
return bot.osd("Please present a query to search.")
query = spicemanip.main(triggerargs, 0)
searchdict = {"query": query, "gifsearch": prefixcommand}
searchdict = {"query": query, "gifsearch": triggercommand}
gifdict = getGif(bot, searchdict)

View File

@ -6,8 +6,6 @@ import sopel.module
from sopel.tools import stderr
from sopel.config.types import StaticSection, ValidatedAttribute
import sopel_modules.osd
from sopel_modules.SpiceBot_Botevents.BotEvents import set_bot_event, check_bot_events, startup_bot_event
from sopel_modules.SpiceBot_CommandsQuery.CommandsQuery import commandsquery_register, commandsquery_register_type
@ -101,7 +99,7 @@ def setup_thread(bot):
@sopel.module.commands('gif')
def gif_trigger(bot, trigger):
triggerargs = sopel_triggerargs(bot, trigger)
triggerargs, triggercommand = sopel_triggerargs(bot, trigger)
if triggerargs == []:
return bot.osd("Please present a query to search.")

View File

@ -0,0 +1,71 @@
# coding=utf-8
from __future__ import unicode_literals, absolute_import, division, print_function
import sopel.module
import spicemanip
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, command_permissions_check, inlist
def configure(config):
pass
def setup(bot):
pass
@sopel.module.nickname_commands('action')
def bot_command_action(bot, trigger):
bot_command_process(bot, trigger)
@sopel.module.nickname_commands('notice')
def bot_command_notice(bot, trigger):
bot_command_process(bot, trigger)
@sopel.module.nickname_commands('privmsg', 'say', 'msg')
def bot_command_privmsg(bot, trigger):
bot_command_process(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.")
return
triggerargs, triggercommand = sopel_triggerargs(bot, trigger, 'nickname_command')
if triggercommand in ['say', 'msg']:
triggercommand = 'privmsg'
if not len(triggerargs):
bot.say("You must specify a channel or nick.")
return
target = spicemanip.main(triggerargs, 1)
if (target not in ['allchans', 'allnicks']
and not inlist(bot, target.lower(), bot.memory['SpiceBot_Channels']['channels'].keys())
and not inlist(bot, target.lower(), bot.users)):
bot.osd("Channel/nick name {} not valid.".format(target))
return
triggerargs = spicemanip.main(triggerargs, '2+', 'list')
if target == 'allchans':
targetsendlist = bot.channels.keys()
elif target == 'allnicks':
targetsendlist = bot.users
else:
targetsendlist = [target]
botmessage = spicemanip.main(triggerargs, 0)
if not botmessage:
bot.say("You must specify a message to send.")
return
bot.osd(botmessage, targetsendlist, triggercommand.upper())

View File

@ -0,0 +1,8 @@
# coding=utf8
from __future__ import unicode_literals, absolute_import, division, print_function
from .Messaging import *
__author__ = 'Sam Zick'
__email__ = 'sam@deathbybandaid.net'
__version__ = '0.1.1'

View File

@ -7,8 +7,6 @@ import sopel.module
from sopel.tools import stderr
from sopel.config.types import StaticSection, ValidatedAttribute
import sopel_modules.osd
from sopel_modules.SpiceBot_SBTools import service_manip

View File

@ -26,16 +26,53 @@ def sopel_triggerargs(bot, trigger, command_type='module_command'):
triggerargs = spicemanip.main(trigger.args[1], 'create')
triggerargs = spicemanip.main(triggerargs, 'create')
if command_type in ['module_command']:
triggerargs = spicemanip.main(triggerargs, '2+', 'list')
elif command_type in ['nickname_command']:
if command_type in ['nickname_command']:
command = spicemanip.main(triggerargs, 2).lower()
triggerargs = spicemanip.main(triggerargs, '3+', 'list')
elif command_type in ['prefix_command']:
prefixcommand = spicemanip.main(triggerargs, 1).lower()[1:]
else:
command = spicemanip.main(triggerargs, 1).lower()[1:]
triggerargs = spicemanip.main(triggerargs, '2+', 'list')
return triggerargs, prefixcommand
return triggerargs
return triggerargs, command
def bot_privs(bot, privtype):
if privtype == 'owners':
privtype = 'owner'
botpriveval = eval("bot.config.core." + privtype)
if not isinstance(botpriveval, list):
botpriveval = [botpriveval]
return botpriveval
def command_permissions_check(bot, trigger, privslist):
commandrunconsensus = []
for botpriv in ["admins", "owner"]:
if botpriv in privslist:
botpriveval = bot_privs(bot, botpriv)
if not inlist(bot, trigger.nick, botpriveval):
commandrunconsensus.append('False')
else:
commandrunconsensus.append('True')
if not trigger.is_privmsg:
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):
commandrunconsensus.append('False')
else:
commandrunconsensus.append('True')
if privslist == []:
commandrunconsensus.append('True')
if 'True' not in commandrunconsensus:
return False
return True
"""List Manipulation Functions"""

View File

@ -5,9 +5,6 @@ from __future__ import unicode_literals, absolute_import, division, print_functi
from sopel import module
from sopel.tools import stderr
import sopel_modules.osd
from sopel_modules.SpiceBot_Botevents.BotEvents import set_bot_event, check_bot_events
from sopel_modules.SpiceBot_CommandsQuery.CommandsQuery import commandsquery_register

View File

@ -9,4 +9,4 @@ from .StartupMonologue import *
__author__ = 'Sam Zick'
__email__ = 'sam@deathbybandaid.net'
__version__ = '0.1.0'
__version__ = '0.1.1'

View File

@ -7,11 +7,9 @@ import sopel.module
from sopel.tools import stderr
from sopel.config.types import StaticSection, ValidatedAttribute
import sopel_modules.osd
import spicemanip
from sopel_modules.SpiceBot_SBTools import service_manip, spicebot_update, sopel_triggerargs
from sopel_modules.SpiceBot_SBTools import service_manip, spicebot_update, sopel_triggerargs, command_permissions_check
class SpiceBot_Update_MainSection(StaticSection):
@ -33,7 +31,11 @@ def setup(bot):
@sopel.module.nickname_commands('update')
def nickname_comand_chanstats(bot, trigger):
triggerargs = sopel_triggerargs(bot, trigger, 'nickname_command')
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')
if not len(triggerargs):
commandused = 'nodeps'
@ -46,9 +48,6 @@ def nickname_comand_chanstats(bot, trigger):
triggerargs = spicemanip.main(triggerargs, '2+', 'list')
if not trigger.admin:
bot.say("You are not authorized to perform this function.")
stderr("Recieved Command to update.")
bot.osd("Received command from " + trigger.nick + " to update from Github and restart. Be Back Soon!", bot.channels.keys())

View File

@ -0,0 +1,355 @@
# coding=utf8
"""Sopel OSD
Sopel OSD is a "niche" method of displaying text in a Sopel bot
"""
# 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 stderr, Identifier
from sopel.config.types import StaticSection, ValidatedAttribute
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("MAXTARGCONFIG", MAXTARGCONFIG, validate=False)
config.MAXTARGCONFIG.configure_setting('notice', 'MAXTARG limit for NOTICE')
config.MAXTARGCONFIG.configure_setting('privmsg', 'MAXTARG limit for PRIVMSG')
def setup(bot):
# Inject OSD
stderr("[Sopel-OSD] Implanting OSD function into bot.")
bot.osd = SopelOSD.osd
bot.SopelWrapper.osd = SopelOSD.SopelWrapper.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
stderr("[Sopel-OSD] Overwrite Default Sopel messaging commands.")
bot.SopelWrapper.say = SopelOSD.SopelWrapper.say
bot.SopelWrapper.action = SopelOSD.SopelWrapper.action
bot.SopelWrapper.notice = SopelOSD.SopelWrapper.notice
bot.SopelWrapper.reply = SopelOSD.SopelWrapper.reply
# verify config settings for server
stderr("[Sopel-OSD] Checking for config settings.")
bot.config.define_section("MAXTARGCONFIG", MAXTARGCONFIG, validate=False)
# RPL_ISUPPORT = '005'
@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.MAXTARGCONFIG.notice = int(value)
elif settingname.upper() == 'PRIVMSG':
bot.config.MAXTARGCONFIG.privmsg = int(value)
class MAXTARGCONFIG(StaticSection):
notice = ValidatedAttribute('notice', default=1)
privmsg = ValidatedAttribute('privmsg', default=1)
class ToolsOSD:
def get_message_recipientgroups(bot, recipients, text_method):
"""
Split recipients into groups based on server capabilities.
This defaults to 4
Input can be
* unicode string
* a comma-seperated unicode string
* list
* dict_keys handy for bot.channels.keys()
"""
if sys.version_info.major >= 3:
if isinstance(recipients, abc.KeysView):
recipients = [x for x in recipients]
if isinstance(recipients, dict):
recipients = [x for x in recipients]
if not isinstance(recipients, list):
recipients = recipients.split(",")
if not len(recipients):
raise ValueError("Recipients list empty.")
if text_method == 'NOTICE':
maxtargets = bot.config.MAXTARGCONFIG.notice
elif text_method in ['PRIVMSG', 'ACTION']:
maxtargets = bot.config.MAXTARGCONFIG.privmsg
maxtargets = int(maxtargets)
recipientgroups = []
while len(recipients):
recipients_part = ','.join(x for x in recipients[-maxtargets:])
recipientgroups.append(recipients_part)
del recipients[-maxtargets:]
return recipientgroups
def get_available_message_bytes(bot, recipientgroups):
"""
Get total available bytes for sending a message line
Total sendable bytes is 512
* 15 are reserved for basic IRC NOTICE/PRIVMSG and a small buffer.
* The bots hostmask plays a role in this count
Note: if unavailable, we calculate the maximum length of a hostmask
* The recipients we send to also is a factor. Multiple recipients reduces
sendable message length
"""
available_bytes = 512
reserved_irc_bytes = 15
available_bytes -= reserved_irc_bytes
try:
hostmaskbytes = len((bot.users.get(bot.nick).hostmask).encode('utf-8'))
except AttributeError:
hostmaskbytes = len((bot.nick).encode('utf-8')) + 12 + 63
available_bytes -= hostmaskbytes
groupbytes = []
for recipients_part in recipientgroups:
groupbytes.append(len((recipients_part).encode('utf-8')))
max_recipients_bytes = max(groupbytes)
available_bytes -= max_recipients_bytes
return available_bytes
def get_sendable_message_list(messages, max_length=400):
"""Get a sendable ``text`` message list.
:param str txt: unicode string of text to send
:param int max_length: maximum length of the message to be sendable
:return: a tuple of two values, the sendable text and its excess text
We're arbitrarily saying that the max is 400 bytes of text when
messages will be split. Otherwise, we'd have to account for the bot's
hostmask, which is hard.
The `max_length` is the max length of text in **bytes**, but we take
care of unicode 2-bytes characters, by working on the unicode string,
then making sure the bytes version is smaller than the max length.
"""
if not isinstance(messages, list):
messages = [messages]
messages_list = ['']
message_padding = 4 * " "
for message in messages:
if len((messages_list[-1] + message_padding + message).encode('utf-8')) <= max_length:
if messages_list[-1] == '':
messages_list[-1] = message
else:
messages_list[-1] = messages_list[-1] + message_padding + message
else:
text_list = []
while len(message.encode('utf-8')) > max_length:
last_space = message.rfind(' ', 0, max_length)
if last_space == -1:
# No last space, just split where it is possible
text_list.append(message[:max_length])
message = message[max_length:]
else:
# Split at the last best space found
text_list.append(message[:last_space])
message = message[last_space:]
if len(message.encode('utf-8')):
text_list.append(message)
messages_list.extend(text_list)
return messages_list
class SopelOSD:
def osd(self, messages, recipients=None, text_method='PRIVMSG', max_messages=-1):
"""Send ``text`` as a PRIVMSG, CTCP ACTION, or NOTICE to ``recipients``.
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.
By default, unless specified in the configuration file, there is some
built-in flood protection. Messages displayed over 5 times in 2 minutes
will be displayed as '...'.
The ``recipient`` can be in list format or a comma seperated string,
with the ability to send to multiple recipients simultaneously. The
default recipients that the bot will send to is 4 if the IRC server
doesn't specify a limit for TARGMAX.
Text can be sent to this function in either string or list format.
List format will insert as small buffering space between entries in the
list.
There are 512 bytes available in a single IRC message. This includes
hostmask of the bot as well as around 15 bytes of reserved IRC message
type. This also includes the destinations/recipients of the message.
This will split given strings/lists into a displayable format as close
to the maximum 512 bytes as possible.
If ``max_messages`` is given, the split mesage will display in as many
lines specified by this argument. Specifying ``0`` or a negative number
will display without limitation. By default this is set to ``-1`` when
called directly. When called from the say/msg/reply/notice/action it
will default to ``1``.
"""
text_method = text_method.upper()
if text_method == 'SAY' or text_method not in ['NOTICE', 'ACTION']:
text_method = 'PRIVMSG'
recipientgroups = tools.get_message_recipientgroups(self, recipients, text_method)
available_bytes = tools.get_available_message_bytes(self, recipientgroups)
messages_list = tools.get_sendable_message_list(messages, available_bytes)
if max_messages >= 1:
messages_list = messages_list[:max_messages]
text_method_orig = text_method
for recipientgroup in recipientgroups:
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_stack = self.stack.setdefault(recipient_id, {
'messages': [],
'flood_left': 4,
'dots': 0,
# TODO
# 'flood_left': self.config.core.flood_burst_lines,
})
recipient_stack['dots'] = 0
for text in messages_list:
try:
self.sending.acquire()
if not recipient_stack['flood_left']:
elapsed = time.time() - recipient_stack['messages'][-1][0]
# TODO
# recipient_stack['flood_left'] = min(
# self.config.core.flood_burst_lines,
# int(elapsed) * self.config.core.flood_refill_rate)
recipient_stack['flood_left'] = min(4, int(elapsed) * 1)
if not recipient_stack['flood_left']:
elapsed = time.time() - recipient_stack['messages'][-1][0]
penalty = float(max(0, len(text) - 50)) / 70
# Never wait more than 2 seconds
# wait = min(self.config.core.flood_empty_wait + penalty, 2) # TODO
wait = min(0.7 + penalty, 2)
if elapsed < wait:
time.sleep(wait - elapsed)
# Loop detection
messages = [m[1] for m in recipient_stack['messages'][-8:]]
# If what we about to send repeated at least 5 times in the
# last 2 minutes, replace with '...'
if messages.count(text) >= 5 and elapsed < 120:
recipient_stack['dots'] += 1
else:
recipient_stack['dots'] = 0
if not recipient_stack['dots'] >= 3:
recipient_stack['flood_left'] = max(0, recipient_stack['flood_left'] - 1)
recipient_stack['messages'].append((time.time(), self.safe(text)))
recipient_stack['messages'] = recipient_stack['messages'][-10:]
if recipient_stack['dots']:
text = '...'
if text_method == 'ACTION':
text_method = 'PRIVMSG'
if text_method == 'ACTION':
text = '\001ACTION {}\001'.format(text)
self.write(('PRIVMSG', recipientgroup), text)
text_method = 'PRIVMSG'
elif text_method == 'NOTICE':
self.write(('NOTICE', recipientgroup), text)
else:
self.write(('PRIVMSG', recipientgroup), text)
finally:
self.sending.release()
class SopelWrapper(object):
def osd(self, messages, recipients=None, text_method='PRIVMSG', max_messages=-1):
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)
# self._bot.say(message, destination, max_messages)
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)
# self._bot.action(message, destination, max_messages)
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)
# self._bot.notice(message, destination, max_messages)
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)
# self._bot.reply(message, destination, reply_to, notice, max_messages)