|
|
|
@ -3,6 +3,32 @@ from pathlib import Path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Plugin:
|
|
|
|
|
"""Base class for the bot plugins.
|
|
|
|
|
|
|
|
|
|
This class provides a lot of tools to facilitate the implementation of
|
|
|
|
|
plugins. Callbacks for all events handled by the IRC library can be
|
|
|
|
|
implemented here (if the Bot class supports it). Most bot features are put
|
|
|
|
|
in plugins to avoid cluttering the Bot class, and no plugins should be
|
|
|
|
|
required for the bot to run; plugins can depend on each other though.
|
|
|
|
|
|
|
|
|
|
A plugin loads his basic information from the config file. It can use the
|
|
|
|
|
bot's runtime values facilities to make runtime values available to other
|
|
|
|
|
plugins. It can also save data using the Bot's storage feature to be
|
|
|
|
|
available after a restart.
|
|
|
|
|
|
|
|
|
|
Initalisation should be very fast, no network connections or anything. They
|
|
|
|
|
are initialised before connecting to the server, so their `is_ready` flag is
|
|
|
|
|
set at that point. The loading order is more or less random, so a plugin
|
|
|
|
|
cannot assume another has been loaded during initialisation. If it wants to
|
|
|
|
|
interact with another plugin, the earliest point to do that is in the
|
|
|
|
|
on_welcome callback which is called after connecting to a server, and can
|
|
|
|
|
disable itself by setting its own `is_ready` flag to false.
|
|
|
|
|
|
|
|
|
|
Plugins can have priorities and calling their callbacks will respect it.
|
|
|
|
|
For now these levels are used:
|
|
|
|
|
- 0: default
|
|
|
|
|
- -3: low, misc parsing of messages, answer to various messages
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
REQUIRED_CONFIGS = []
|
|
|
|
|
|
|
|
|
@ -109,7 +135,14 @@ class Plugin:
|
|
|
|
|
return first_word_and_rest[1].strip()
|
|
|
|
|
|
|
|
|
|
def should_answer_question(self, message):
|
|
|
|
|
"""Store Question in object and return True if it should answer it."""
|
|
|
|
|
"""Store Question in object and return True if I should answer it.
|
|
|
|
|
|
|
|
|
|
To answer a question, the message must start with one of the bot's names
|
|
|
|
|
and optionally end with one or more question marks (they are discarded).
|
|
|
|
|
The bot checks that answering conditions are respected, and they cannot
|
|
|
|
|
be bypassed as with commands. A Question created is checked from the
|
|
|
|
|
plugin's registered questions and stored in the instance.
|
|
|
|
|
"""
|
|
|
|
|
words = message.split()
|
|
|
|
|
# Is the message addressed to me?
|
|
|
|
|
if len(words) == 0 or words[0].lower() not in self.bot.names:
|
|
|
|
@ -139,7 +172,7 @@ class Plugin:
|
|
|
|
|
no_content=False,
|
|
|
|
|
exclude_conditions=None,
|
|
|
|
|
):
|
|
|
|
|
"""Store Command in object and return True if it should handle it.
|
|
|
|
|
"""Store Command in object and return True if I should handle it.
|
|
|
|
|
|
|
|
|
|
If no_content is True, the command does not parse command contents and
|
|
|
|
|
put all the command message (without suffix) to the command identifier.
|
|
|
|
@ -193,10 +226,10 @@ class Plugin:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def __parse_command(self, message, no_content=False):
|
|
|
|
|
"""Return a command ID if this message is a command.
|
|
|
|
|
"""Return a parsed Command if this message is a command, None otherwise.
|
|
|
|
|
|
|
|
|
|
The command raw field is always set. The ident and content fields are
|
|
|
|
|
not set when no_content is True. The match field is never set by this
|
|
|
|
|
empty when no_content is True. The match field is never set by this
|
|
|
|
|
method.
|
|
|
|
|
"""
|
|
|
|
|
words = message.split()
|
|
|
|
|