v0.0.2: answer capability
This commit is contained in:
@@ -115,6 +115,10 @@ bot.start() # blocking function
|
|||||||
* Change the game status every n seconds.
|
* Change the game status every n seconds.
|
||||||
* `error_restart_delay` (default: `2`)
|
* `error_restart_delay` (default: `2`)
|
||||||
* On crash, restart after n seconds.
|
* On crash, restart after n seconds.
|
||||||
|
* `answer` (default: `True`)
|
||||||
|
* Use the answer capability on `help` and `info` functions
|
||||||
|
* `answer_mention` (default: `True`)
|
||||||
|
* Mention author in the answer
|
||||||
|
|
||||||
### Registering commands
|
### Registering commands
|
||||||
|
|
||||||
@@ -325,6 +329,7 @@ bot.start() # this bot respond to "|help", "|info" and "|hello"
|
|||||||
|
|
||||||
## Versions
|
## Versions
|
||||||
|
|
||||||
|
* v0.0.2 : new answer capability
|
||||||
* v0.0.1 : initial version
|
* v0.0.1 : initial version
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|||||||
+73
-30
@@ -13,7 +13,9 @@ from dotenv import load_dotenv
|
|||||||
|
|
||||||
from ._utils import sanitize_input, parse_arguments
|
from ._utils import sanitize_input, parse_arguments
|
||||||
|
|
||||||
CommandFunction = Callable[[discord.Client, discord.Message, Tuple[str]], Coroutine[Any, Any, None]]
|
CommandFunction = Callable[
|
||||||
|
[discord.Client, discord.Message, Tuple[str]], Coroutine[Any, Any, None]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def debug(message: discord.Message, txt: str):
|
def debug(message: discord.Message, txt: str):
|
||||||
@@ -21,7 +23,9 @@ def debug(message: discord.Message, txt: str):
|
|||||||
|
|
||||||
|
|
||||||
class Command(object):
|
class Command(object):
|
||||||
def __init__(self, regex: str, compute: CommandFunction, help_short: str, help_long: str):
|
def __init__(
|
||||||
|
self, regex: str, compute: CommandFunction, help_short: str, help_long: str
|
||||||
|
):
|
||||||
self.regex = regex
|
self.regex = regex
|
||||||
self.compute = compute
|
self.compute = compute
|
||||||
self.help_short = help_short
|
self.help_short = help_short
|
||||||
@@ -41,6 +45,8 @@ class Bot(object):
|
|||||||
self.lower_command_names = True
|
self.lower_command_names = True
|
||||||
self.game_change_delay = 10
|
self.game_change_delay = 10
|
||||||
self.error_restart_delay = 2
|
self.error_restart_delay = 2
|
||||||
|
self.answer = True
|
||||||
|
self.answer_mention = False
|
||||||
# config vars
|
# config vars
|
||||||
self.app_name = app_name
|
self.app_name = app_name
|
||||||
self.version = version
|
self.version = version
|
||||||
@@ -52,11 +58,11 @@ class Bot(object):
|
|||||||
self.__watcher = None
|
self.__watcher = None
|
||||||
self.__commands = []
|
self.__commands = []
|
||||||
self.__fallback = None
|
self.__fallback = None
|
||||||
self.games = [f"v{version}",
|
self.games = [f"v{version}", lambda: f"{len(self.client.guilds)} guilds"]
|
||||||
lambda:f"{len(self.client.guilds)} guilds"]
|
|
||||||
if self.alias is not None:
|
if self.alias is not None:
|
||||||
self.games += [f"{self.alias}help"]
|
self.games += [f"{self.alias}help"]
|
||||||
self.client = discord.Client()
|
self.client = discord.Client()
|
||||||
|
self.client.bot = self
|
||||||
self.__register_events()
|
self.__register_events()
|
||||||
self.__register_commands()
|
self.__register_commands()
|
||||||
|
|
||||||
@@ -68,22 +74,23 @@ class Bot(object):
|
|||||||
|
|
||||||
def __register_commands(self):
|
def __register_commands(self):
|
||||||
# register default commands
|
# register default commands
|
||||||
tmp_alias = '' if self.alias is None else self.alias
|
tmp_alias = "" if self.alias is None else self.alias
|
||||||
self.register_command(
|
self.register_command(
|
||||||
"(help|h)", self.help, "help: show this help",
|
"(help|h)",
|
||||||
|
self.help,
|
||||||
|
"help: show this help",
|
||||||
f"```\n"
|
f"```\n"
|
||||||
f"* {tmp_alias}help\n"
|
f"* {tmp_alias}help\n"
|
||||||
f"\tShows the list of commands.\n"
|
f"\tShows the list of commands.\n"
|
||||||
f"* {tmp_alias}help [command]\n"
|
f"* {tmp_alias}help [command]\n"
|
||||||
f"\tShows help about a specific command.\n"
|
f"\tShows help about a specific command.\n"
|
||||||
f"```"
|
f"```",
|
||||||
)
|
)
|
||||||
self.register_command(
|
self.register_command(
|
||||||
"(info|about)", self.info, "info: show description",
|
"(info|about)",
|
||||||
f"```\n"
|
self.info,
|
||||||
f"* {tmp_alias}info:\n"
|
"info: show description",
|
||||||
f"\tShows this bot's status.\n"
|
f"```\n" f"* {tmp_alias}info:\n" f"\tShows this bot's status.\n" f"```",
|
||||||
f"```"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def __generate_game(self) -> str:
|
def __generate_game(self) -> str:
|
||||||
@@ -99,35 +106,55 @@ class Bot(object):
|
|||||||
f"{self.app_name} v{self.version}\n"
|
f"{self.app_name} v{self.version}\n"
|
||||||
f"* Started at {self.__t0:%Y-%m-%d %H:%M}\n"
|
f"* Started at {self.__t0:%Y-%m-%d %H:%M}\n"
|
||||||
f"* Connected to {len(self.client.guilds)} guilds\n"
|
f"* Connected to {len(self.client.guilds)} guilds\n"
|
||||||
f"```"
|
f"```",
|
||||||
|
reference=message if self.answer else None,
|
||||||
|
mention_author=self.answer_mention,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def help(self, _client: discord.client, message: discord.Message, *args: str):
|
async def help(self, _client: discord.client, message: discord.Message, *args: str):
|
||||||
if len(args) <= 1:
|
if len(args) <= 1:
|
||||||
tmp_alias = '' if self.alias is None else self.alias
|
tmp_alias = "" if self.alias is None else self.alias
|
||||||
await message.channel.send(
|
await message.channel.send(
|
||||||
"```\n"
|
"```\n"
|
||||||
"List of available commands:\n"
|
"List of available commands:\n"
|
||||||
+ "".join([f"* {tmp_alias}{command.help_short}\n" for command in self.__commands])
|
+ "".join(
|
||||||
+ "```"
|
[
|
||||||
|
f"* {tmp_alias}{command.help_short}\n"
|
||||||
|
for command in self.__commands
|
||||||
|
]
|
||||||
|
)
|
||||||
|
+ "```",
|
||||||
|
reference=message if self.answer else None,
|
||||||
|
mention_author=self.answer_mention,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
for command in self.__commands:
|
for command in self.__commands:
|
||||||
if re.match(command.regex, args[1].lower() if self.lower_command_names else args[1]):
|
if re.match(
|
||||||
|
command.regex,
|
||||||
|
args[1].lower() if self.lower_command_names else args[1],
|
||||||
|
):
|
||||||
await message.channel.send(command.help_long)
|
await message.channel.send(command.help_long)
|
||||||
return
|
return
|
||||||
await message.channel.send(f"Command `{sanitize_input(args[1])}` not found")
|
await message.channel.send(
|
||||||
|
f"Command `{sanitize_input(args[1])}` not found",
|
||||||
|
reference=message if self.answer else None,
|
||||||
|
mention_author=self.answer_mention,
|
||||||
|
)
|
||||||
|
|
||||||
async def on_ready(self):
|
async def on_ready(self):
|
||||||
# Change status
|
# Change status
|
||||||
logging.info(f"{self.client.user} (v{self.version}) has connected to {len(self.client.guilds)} Discord guilds")
|
logging.info(
|
||||||
if self.guild_logs_file is not None and not os.path.exists(self.guild_logs_file):
|
f"{self.client.user} (v{self.version}) has connected to {len(self.client.guilds)} Discord guilds"
|
||||||
|
)
|
||||||
|
if self.guild_logs_file is not None and not os.path.exists(
|
||||||
|
self.guild_logs_file
|
||||||
|
):
|
||||||
for guild in self.client.guilds:
|
for guild in self.client.guilds:
|
||||||
await self.on_guild_join(guild)
|
await self.on_guild_join(guild)
|
||||||
while True:
|
while True:
|
||||||
await self.client.change_presence(
|
await self.client.change_presence(
|
||||||
activity=discord.Game(self.__generate_game()),
|
activity=discord.Game(self.__generate_game()),
|
||||||
status=discord.Status.online
|
status=discord.Status.online,
|
||||||
)
|
)
|
||||||
await asyncio.sleep(self.game_change_delay)
|
await asyncio.sleep(self.game_change_delay)
|
||||||
|
|
||||||
@@ -140,13 +167,18 @@ class Bot(object):
|
|||||||
|
|
||||||
is_direct = message.channel.type == discord.ChannelType.private
|
is_direct = message.channel.type == discord.ChannelType.private
|
||||||
|
|
||||||
is_mention = self.any_mention and self.client.user in message.mentions \
|
is_mention = (
|
||||||
|
self.any_mention
|
||||||
|
and self.client.user in message.mentions
|
||||||
or bool(re.match(f"^<@!?{self.client.user.id}>", message.content))
|
or bool(re.match(f"^<@!?{self.client.user.id}>", message.content))
|
||||||
|
)
|
||||||
|
|
||||||
if self.remove_mentions:
|
if self.remove_mentions:
|
||||||
message.content = re.sub(r"<@!?[^>]+>", "", message.content)
|
message.content = re.sub(r"<@!?[^>]+>", "", message.content)
|
||||||
elif is_mention:
|
elif is_mention:
|
||||||
message.content = re.sub(f"^<@!?{self.client.user.id}>", "", message.content)
|
message.content = re.sub(
|
||||||
|
f"^<@!?{self.client.user.id}>", "", message.content
|
||||||
|
)
|
||||||
|
|
||||||
command_args = parse_arguments(message.content)
|
command_args = parse_arguments(message.content)
|
||||||
|
|
||||||
@@ -157,7 +189,7 @@ class Bot(object):
|
|||||||
|
|
||||||
is_alias = self.alias is not None and command_args[0].startswith(self.alias)
|
is_alias = self.alias is not None and command_args[0].startswith(self.alias)
|
||||||
if is_alias: # remove alias from first arg
|
if is_alias: # remove alias from first arg
|
||||||
command_args[0] = command_args[0][len(self.alias):]
|
command_args[0] = command_args[0][len(self.alias) :]
|
||||||
|
|
||||||
if not is_direct and not is_mention and not is_alias:
|
if not is_direct and not is_mention and not is_alias:
|
||||||
return # Not for the bot
|
return # Not for the bot
|
||||||
@@ -165,7 +197,12 @@ class Bot(object):
|
|||||||
command_found = False
|
command_found = False
|
||||||
|
|
||||||
for command in self.__commands:
|
for command in self.__commands:
|
||||||
if re.match(command.regex, command_args[0].lower() if self.lower_command_names else command_args[0]):
|
if re.match(
|
||||||
|
command.regex,
|
||||||
|
command_args[0].lower()
|
||||||
|
if self.lower_command_names
|
||||||
|
else command_args[0],
|
||||||
|
):
|
||||||
if self.log_calls:
|
if self.log_calls:
|
||||||
debug(message, str(command_args))
|
debug(message, str(command_args))
|
||||||
|
|
||||||
@@ -175,7 +212,7 @@ class Bot(object):
|
|||||||
if not permissions.send_messages:
|
if not permissions.send_messages:
|
||||||
await message.author.create_dm()
|
await message.author.create_dm()
|
||||||
await message.author.dm_channel.send(
|
await message.author.dm_channel.send(
|
||||||
f"Hi, this bot doesn\'t have the permission to send a message to"
|
f"Hi, this bot doesn't have the permission to send a message to"
|
||||||
f" #{message.channel} in server '{message.guild}'"
|
f" #{message.channel} in server '{message.guild}'"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
@@ -196,7 +233,9 @@ class Bot(object):
|
|||||||
with open(self.guild_logs_file, encoding="utf-8", mode="a") as f:
|
with open(self.guild_logs_file, encoding="utf-8", mode="a") as f:
|
||||||
f.write(f"{datetime.now():%Y-%m-%d %H:%M} -{guild.id}: {guild.name}\n")
|
f.write(f"{datetime.now():%Y-%m-%d %H:%M} -{guild.id}: {guild.name}\n")
|
||||||
|
|
||||||
def register_command(self, regex: str, compute: CommandFunction, help_short: str, help_long: str):
|
def register_command(
|
||||||
|
self, regex: str, compute: CommandFunction, help_short: str, help_long: str
|
||||||
|
):
|
||||||
if not regex.startswith("^"):
|
if not regex.startswith("^"):
|
||||||
regex = "^" + regex
|
regex = "^" + regex
|
||||||
if not regex.endswith("$"):
|
if not regex.endswith("$"):
|
||||||
@@ -216,9 +255,13 @@ class Bot(object):
|
|||||||
self.__token = os.getenv(self.token_env_var)
|
self.__token = os.getenv(self.token_env_var)
|
||||||
if self.__token is None:
|
if self.__token is None:
|
||||||
if path.exists(env_file) and env_file_found:
|
if path.exists(env_file) and env_file_found:
|
||||||
raise EnvironmentError(f"No token was loaded, please verify your .env file has '{self.token_env_var}'")
|
raise EnvironmentError(
|
||||||
|
f"No token was loaded, please verify your .env file has '{self.token_env_var}'"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise EnvironmentError(f"No environment variable '{self.token_env_var}' found")
|
raise EnvironmentError(
|
||||||
|
f"No environment variable '{self.token_env_var}' found"
|
||||||
|
)
|
||||||
self.__t0 = datetime.now()
|
self.__t0 = datetime.now()
|
||||||
# Launch client and rerun on errors
|
# Launch client and rerun on errors
|
||||||
while True:
|
while True:
|
||||||
@@ -231,7 +274,7 @@ class Bot(object):
|
|||||||
if repr(e) != self.__last_error:
|
if repr(e) != self.__last_error:
|
||||||
self.__last_error = repr(e)
|
self.__last_error = repr(e)
|
||||||
filename = f"error_{t:%Y-%m-%d_%H-%M-%S}.txt"
|
filename = f"error_{t:%Y-%m-%d_%H-%M-%S}.txt"
|
||||||
with open(filename, 'w') as f:
|
with open(filename, "w") as f:
|
||||||
f.write(
|
f.write(
|
||||||
f"{self.app_name} v{self.version} started at {self.__t0:%Y-%m-%d %H:%M}\r\n"
|
f"{self.app_name} v{self.version} started at {self.__t0:%Y-%m-%d %H:%M}\r\n"
|
||||||
f"Exception raised at {t:%Y-%m-%d %H:%M}\r\n"
|
f"Exception raised at {t:%Y-%m-%d %H:%M}\r\n"
|
||||||
|
|||||||
+2
-2
@@ -1,2 +1,2 @@
|
|||||||
discord
|
discord.py
|
||||||
python-dotenv
|
python-dotenv
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
|
|||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name="miniscord-Klemek",
|
name="miniscord-Klemek",
|
||||||
version="0.0.1",
|
version="0.0.2",
|
||||||
author="Klemek",
|
author="Klemek",
|
||||||
description="A minimalist discord bot API",
|
description="A minimalist discord bot API",
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
@@ -17,5 +17,5 @@ setuptools.setup(
|
|||||||
"License :: OSI Approved :: GNU License",
|
"License :: OSI Approved :: GNU License",
|
||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
],
|
],
|
||||||
python_requires='>=3.6',
|
python_requires=">=3.6",
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user