diff --git a/README.md b/README.md index 396de59..4eeb270 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,10 @@ bot.start() # blocking function * Change the game status every n seconds. * `error_restart_delay` (default: `2`) * 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 @@ -325,6 +329,7 @@ bot.start() # this bot respond to "|help", "|info" and "|hello" ## Versions +* v0.0.2 : new answer capability * v0.0.1 : initial version ## TODO diff --git a/miniscord/_bot.py b/miniscord/_bot.py index ba313d7..0de277c 100644 --- a/miniscord/_bot.py +++ b/miniscord/_bot.py @@ -13,7 +13,9 @@ from dotenv import load_dotenv 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): @@ -21,7 +23,9 @@ def debug(message: discord.Message, txt: str): 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.compute = compute self.help_short = help_short @@ -41,6 +45,8 @@ class Bot(object): self.lower_command_names = True self.game_change_delay = 10 self.error_restart_delay = 2 + self.answer = True + self.answer_mention = False # config vars self.app_name = app_name self.version = version @@ -52,11 +58,11 @@ class Bot(object): self.__watcher = None self.__commands = [] self.__fallback = None - self.games = [f"v{version}", - lambda:f"{len(self.client.guilds)} guilds"] + self.games = [f"v{version}", lambda: f"{len(self.client.guilds)} guilds"] if self.alias is not None: self.games += [f"{self.alias}help"] self.client = discord.Client() + self.client.bot = self self.__register_events() self.__register_commands() @@ -68,22 +74,23 @@ class Bot(object): def __register_commands(self): # 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( - "(help|h)", self.help, "help: show this help", + "(help|h)", + self.help, + "help: show this help", f"```\n" f"* {tmp_alias}help\n" f"\tShows the list of commands.\n" f"* {tmp_alias}help [command]\n" f"\tShows help about a specific command.\n" - f"```" + f"```", ) self.register_command( - "(info|about)", self.info, "info: show description", - f"```\n" - f"* {tmp_alias}info:\n" - f"\tShows this bot's status.\n" - f"```" + "(info|about)", + self.info, + "info: show description", + f"```\n" f"* {tmp_alias}info:\n" f"\tShows this bot's status.\n" f"```", ) def __generate_game(self) -> str: @@ -99,35 +106,55 @@ class Bot(object): f"{self.app_name} v{self.version}\n" f"* Started at {self.__t0:%Y-%m-%d %H:%M}\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): 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( "```\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: 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) 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): # Change status - logging.info(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): + logging.info( + 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: await self.on_guild_join(guild) while True: await self.client.change_presence( activity=discord.Game(self.__generate_game()), - status=discord.Status.online + status=discord.Status.online, ) await asyncio.sleep(self.game_change_delay) @@ -140,13 +167,18 @@ class Bot(object): 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)) + ) if self.remove_mentions: message.content = re.sub(r"<@!?[^>]+>", "", message.content) 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) @@ -157,7 +189,7 @@ class Bot(object): is_alias = self.alias is not None and command_args[0].startswith(self.alias) 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: return # Not for the bot @@ -165,7 +197,12 @@ class Bot(object): command_found = False 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: debug(message, str(command_args)) @@ -175,7 +212,7 @@ class Bot(object): if not permissions.send_messages: await message.author.create_dm() 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}'" ) return @@ -196,7 +233,9 @@ class Bot(object): 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") - 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("^"): regex = "^" + regex if not regex.endswith("$"): @@ -216,9 +255,13 @@ class Bot(object): self.__token = os.getenv(self.token_env_var) if self.__token is None: 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: - 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() # Launch client and rerun on errors while True: @@ -231,7 +274,7 @@ class Bot(object): if repr(e) != self.__last_error: self.__last_error = repr(e) 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"{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" diff --git a/requirements.txt b/requirements.txt index c47d7a8..a41d83f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -discord -python-dotenv \ No newline at end of file +discord.py +python-dotenv diff --git a/setup.py b/setup.py index f0ca720..ef44774 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ with open("README.md", "r") as fh: setuptools.setup( name="miniscord-Klemek", - version="0.0.1", + version="0.0.2", author="Klemek", description="A minimalist discord bot API", long_description=long_description, @@ -17,5 +17,5 @@ setuptools.setup( "License :: OSI Approved :: GNU License", "Operating System :: OS Independent", ], - python_requires='>=3.6', + python_requires=">=3.6", )