VocalMaisBot/utils/discord_utils.py

68 lines
2.3 KiB
Python

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})"