import discord import discord.ext.commands as commands from functools import singledispatch class CheckFailDoNotNotify(commands.CheckFailure): """ A custom exception that we can raise inside command check functions if the check fails, but the global error handling should not notify the user about the error. For example it can be used if the check function already sent the user a customised error message. """ pass def voice_channel_safe_name(template: str, max_chars: int = 100, escape_mentions: bool = True, escape_markdown: bool = False, user_name_replacement: str = None) -> str: """ Make a name that is suitable for naming voice channels from a template (e.g. found in the config file or given by a user) :param template: The template used as basis for the name :param max_chars: The name is ellipsed if it exceeds this number of characters. For a discord voice channel, it is currently 100 chars :param escape_mentions: If true, escape role and user mentions :param escape_markdown: If true, escape discord's markdown. For now, discord does not support markdown in channel names anyways :param user_name_replacement: If not None, replace occurrences of '{user}' in the message with this value """ message = template if user_name_replacement is not None: message = message.replace("{user}", user_name_replacement) if escape_mentions: message = discord.utils.escape_mentions(message) if escape_markdown: message = discord.utils.escape_markdown(message) if len(message) > max_chars: message = message[:max_chars - 3] + "..." return message @singledispatch def to_string(obj) -> str: """ Convert the given discord object to a string, for logging purposes. See functools.singledispatch """ return str(obj) @to_string.register(discord.Object) @to_string.register(discord.abc.Snowflake) def _(obj) -> str: return f"<{obj.id}>" @to_string.register(discord.abc.User) def _(user) -> str: return f"{user.name}#{user.discriminator}({user.id})" @to_string.register(discord.Guild) def _(guild) -> str: return f"{guild.name}({guild.id})" # Even though these types are all subclasses of discord.abc.GuildChannel, it does not work if we register that class directly @to_string.register(discord.TextChannel) @to_string.register(discord.VoiceChannel) @to_string.register(discord.CategoryChannel) def _(channel) -> str: return f"{channel.name}({channel.id})"