async def before(self, ctx: commands.Context, message_id: int, number: int, delete_pinned: bool = False): """Deletes X messages before specified message. To get a message id, enable developer mode in Discord's settings, 'appearance' tab. Then right click a message and copy its id. """ channel = ctx.channel author = ctx.author try: before = await channel.get_message(message_id) except discord.NotFound: return await ctx.send(_("Message not found.")) to_delete = await self.get_messages_for_deletion( channel=channel, number=number, before=before, delete_pinned=delete_pinned) to_delete.append(ctx.message) reason = "{}({}) deleted {} messages in channel {}.".format( author.name, author.id, len(to_delete), channel.name) log.info(reason) await mass_purge(to_delete, channel)
async def messages(self, ctx: commands.Context, number: int, delete_pinned: bool = False): """Delete the last X messages. Example: `[p]cleanup messages 26` """ channel = ctx.channel author = ctx.author if number > 100: cont = await self.check_100_plus(ctx, number) if not cont: return to_delete = await self.get_messages_for_deletion( channel=channel, number=number, before=ctx.message, delete_pinned=delete_pinned ) to_delete.append(ctx.message) reason = "{}({}) deleted {} messages in channel {}.".format( author.name, author.id, number, channel.name ) log.info(reason) await mass_purge(to_delete, channel)
async def messages(self, ctx: commands.Context, number: int, delete_pinned: bool = False): """Delete the last X messages. Example: `[p]cleanup messages 26` """ channel = ctx.channel author = ctx.author if number > 100: cont = await self.check_100_plus(ctx, number) if not cont: return to_delete = await self.get_messages_for_deletion( channel=channel, number=number, before=ctx.message, delete_pinned=delete_pinned) to_delete.append(ctx.message) reason = "{}({}) deleted {} messages in channel {}.".format( author.name, author.id, number, channel.name) log.info(reason) await mass_purge(to_delete, channel)
async def messages(self, ctx: commands.Context, number: int, delete_pinned: bool = False): """Deletes last X messages. Example: cleanup messages 26""" channel = ctx.channel if not channel.permissions_for(ctx.guild.me).manage_messages: await ctx.send("I need the Manage Messages permission to do this.") return author = ctx.author if number > 100: cont = await self.check_100_plus(ctx, number) if not cont: return to_delete = await self.get_messages_for_deletion( channel=channel, number=number, before=ctx.message, delete_pinned=delete_pinned) to_delete.append(ctx.message) reason = "{}({}) deleted {} messages in channel {}.".format( author.name, author.id, number, channel.name) log.info(reason) await mass_purge(to_delete, channel)
async def after(self, ctx: commands.Context, message_id: int, delete_pinned: bool = False): """Deletes all messages after specified message. To get a message id, enable developer mode in Discord's settings, 'appearance' tab. Then right click a message and copy its id. This command only works on bots running as bot accounts. """ channel = ctx.channel if not channel.permissions_for(ctx.guild.me).manage_messages: await ctx.send("I need the Manage Messages permission to do this.") return author = ctx.author try: after = await channel.get_message(message_id) except discord.NotFound: return await ctx.send(_("Message not found.")) to_delete = await self.get_messages_for_deletion( channel=channel, number=None, after=after, delete_pinned=delete_pinned) reason = "{}({}) deleted {} messages in channel {}.".format( author.name, author.id, len(to_delete), channel.name) log.info(reason) await mass_purge(to_delete, channel)
async def before( self, ctx: commands.Context, message_id: int, number: int, delete_pinned: bool = False ): """Deletes X messages before specified message. To get a message id, enable developer mode in Discord's settings, 'appearance' tab. Then right click a message and copy its id. """ channel = ctx.channel author = ctx.author try: before = await channel.get_message(message_id) except discord.NotFound: return await ctx.send(_("Message not found.")) to_delete = await self.get_messages_for_deletion( channel=channel, number=number, before=before, delete_pinned=delete_pinned ) to_delete.append(ctx.message) reason = "{}({}) deleted {} messages in channel {}.".format( author.name, author.id, len(to_delete), channel.name ) log.info(reason) await mass_purge(to_delete, channel)
async def cleanup_bot(self, ctx: commands.Context, number: int, delete_pinned: bool = False): """Cleans up command messages and messages from the bot.""" channel = ctx.channel if not channel.permissions_for(ctx.guild.me).manage_messages: await ctx.send("I need the Manage Messages permission to do this.") return author = ctx.message.author is_bot = self.bot.user.bot if number > 100: cont = await self.check_100_plus(ctx, number) if not cont: return prefixes = await self.bot.get_prefix( ctx.message) # This returns all server prefixes if isinstance(prefixes, str): prefixes = [prefixes] # In case some idiot sets a null prefix if "" in prefixes: prefixes.remove("") def check(m): if m.author.id == self.bot.user.id: return True elif m == ctx.message: return True p = discord.utils.find(m.content.startswith, prefixes) if p and len(p) > 0: cmd_name = m.content[len(p):].split(" ")[0] return bool(self.bot.get_command(cmd_name)) return False to_delete = await self.get_messages_for_deletion( ctx, channel, number, check=check, limit=1000, before=ctx.message, delete_pinned=delete_pinned, ) to_delete.append(ctx.message) reason = ("{}({}) deleted {} " " command messages in channel {}." "".format(author.name, author.id, len(to_delete), channel.name)) log.info(reason) if is_bot: await mass_purge(to_delete, channel) else: await slow_deletion(to_delete)
async def user(self, ctx: commands.Context, user: str, number: int, delete_pinned: bool = False): """Deletes last X messages from specified user. Examples: cleanup user @\u200bTwentysix 2 cleanup user Red 6""" channel = ctx.channel if not channel.permissions_for(ctx.guild.me).manage_messages: await ctx.send("I need the Manage Messages permission to do this.") return member = None try: member = await commands.converter.MemberConverter().convert( ctx, user) except commands.BadArgument: try: _id = int(user) except ValueError: raise commands.BadArgument() else: _id = member.id author = ctx.author if number > 100: cont = await self.check_100_plus(ctx, number) if not cont: return def check(m): if m.author.id == _id: return True elif m == ctx.message: return True else: return False to_delete = await self.get_messages_for_deletion( channel=channel, number=number, check=check, before=ctx.message, delete_pinned=delete_pinned, ) reason = ("{}({}) deleted {} messages " " made by {}({}) in channel {}." "".format(author.name, author.id, len(to_delete), member or "???", _id, channel.name)) log.info(reason) await mass_purge(to_delete, channel)
async def after(self, ctx: commands.Context, message_id: int, delete_pinned: bool = False): """Deletes all messages after specified message. To get a message id, enable developer mode in Discord's settings, 'appearance' tab. Then right click a message and copy its id. This command only works on bots running as bot accounts. """ channel = ctx.channel if not channel.permissions_for(ctx.guild.me).manage_messages: await ctx.send("I need the Manage Messages permission to do this.") return author = ctx.author is_bot = self.bot.user.bot if not is_bot: await ctx.send( _("This command can only be used on bots with bot accounts.")) return try: message = await channel.get_message(message_id) except discord.NotFound: await ctx.send(_("Message not found.")) return if (ctx.message.created_at - message.created_at).days >= 14: await ctx.send( "The specified message must be less than 14 days old.") return if not delete_pinned: pinned_msgs = await channel.pins() to_exclude = set(m for m in pinned_msgs if m.created_at > message.created_at) else: to_exclude = None if to_exclude: to_delete = await channel.history(limit=None, after=message).flatten() to_delete = set(to_delete) - to_exclude await channel.delete_messages(to_delete) num_deleted = len(to_delete) else: num_deleted = len(await channel.purge(limit=None, after=message)) reason = "{}({}) deleted {} messages in channel {}.".format( author.name, author.id, num_deleted, channel.name) log.info(reason)
async def user( self, ctx: commands.Context, user: str, number: int, delete_pinned: bool = False ): """Delete the last X messages from a specified user. Examples: `[p]cleanup user @\u200bTwentysix 2` `[p]cleanup user Red 6` """ channel = ctx.channel member = None try: member = await commands.MemberConverter().convert(ctx, user) except commands.BadArgument: try: _id = int(user) except ValueError: raise commands.BadArgument() else: _id = member.id author = ctx.author if number > 100: cont = await self.check_100_plus(ctx, number) if not cont: return def check(m): if m.author.id == _id: return True else: return False to_delete = await self.get_messages_for_deletion( channel=channel, number=number, check=check, before=ctx.message, delete_pinned=delete_pinned, ) to_delete.append(ctx.message) reason = ( "{}({}) deleted {} messages " " made by {}({}) in channel {}." "".format(author.name, author.id, len(to_delete), member or "???", _id, channel.name) ) log.info(reason) await mass_purge(to_delete, channel)
async def text(self, ctx: commands.Context, text: str, number: int, delete_pinned: bool = False): """Deletes last X messages matching the specified text. Example: cleanup text \"test\" 5 Remember to use double quotes.""" channel = ctx.channel if not channel.permissions_for(ctx.guild.me).manage_messages: await ctx.send("I need the Manage Messages permission to do this.") return author = ctx.author is_bot = self.bot.user.bot if number > 100: cont = await self.check_100_plus(ctx, number) if not cont: return def check(m): if text in m.content: return True elif m == ctx.message: return True else: return False to_delete = await self.get_messages_for_deletion( ctx, channel, number, check=check, limit=1000, before=ctx.message, delete_pinned=delete_pinned, ) reason = "{}({}) deleted {} messages containing '{}' in channel {}.".format( author.name, author.id, len(to_delete), text, channel.id) log.info(reason) if is_bot: await mass_purge(to_delete, channel) else: await slow_deletion(to_delete)
async def text(self, ctx: commands.Context, text: str, number: int, delete_pinned: bool = False): """Delete the last X messages matching the specified text. Example: `[p]cleanup text "test" 5` Remember to use double quotes. """ channel = ctx.channel author = ctx.author if number > 100: cont = await self.check_100_plus(ctx, number) if not cont: return def check(m): if text in m.content: return True else: return False to_delete = await self.get_messages_for_deletion( channel=channel, number=number, check=check, before=ctx.message, delete_pinned=delete_pinned, ) to_delete.append(ctx.message) reason = "{}({}) deleted {} messages containing '{}' in channel {}.".format( author.name, author.id, len(to_delete), text, channel.id) log.info(reason) await mass_purge(to_delete, channel)
async def text( self, ctx: commands.Context, text: str, number: int, delete_pinned: bool = False ): """Delete the last X messages matching the specified text. Example: `[p]cleanup text "test" 5` Remember to use double quotes. """ channel = ctx.channel author = ctx.author if number > 100: cont = await self.check_100_plus(ctx, number) if not cont: return def check(m): if text in m.content: return True else: return False to_delete = await self.get_messages_for_deletion( channel=channel, number=number, check=check, before=ctx.message, delete_pinned=delete_pinned, ) to_delete.append(ctx.message) reason = "{}({}) deleted {} messages containing '{}' in channel {}.".format( author.name, author.id, len(to_delete), text, channel.id ) log.info(reason) await mass_purge(to_delete, channel)
async def cleanup_self( self, ctx: commands.Context, number: int, match_pattern: str = None, delete_pinned: bool = False, ): """Clean up messages owned by the bot. By default, all messages are cleaned. If a third argument is specified, it is used for pattern matching: If it begins with r( and ends with ), then it is interpreted as a regex, and messages that match it are deleted. Otherwise, it is used in a simple substring test. Some helpful regex flags to include in your pattern: Dots match newlines: (?s); Ignore case: (?i); Both: (?si) """ channel = ctx.channel author = ctx.message.author if number > 100: cont = await self.check_100_plus(ctx, number) if not cont: return # You can always delete your own messages, this is needed to purge can_mass_purge = False if type(author) is discord.Member: me = ctx.guild.me can_mass_purge = channel.permissions_for(me).manage_messages use_re = match_pattern and match_pattern.startswith( "r(") and match_pattern.endswith(")") if use_re: match_pattern = match_pattern[1:] # strip 'r' match_re = re.compile(match_pattern) def content_match(c): return bool(match_re.match(c)) elif match_pattern: def content_match(c): return match_pattern in c else: def content_match(_): return True def check(m): if m.author.id != self.bot.user.id: return False elif content_match(m.content): return True return False to_delete = await self.get_messages_for_deletion( channel=channel, number=number, check=check, before=ctx.message, delete_pinned=delete_pinned, ) if ctx.guild: channel_name = "channel " + channel.name else: channel_name = str(channel) reason = ("{}({}) deleted {} messages " "sent by the bot in {}." "".format(author.name, author.id, len(to_delete), channel_name)) log.info(reason) if can_mass_purge: await mass_purge(to_delete, channel) else: await slow_deletion(to_delete)
async def cleanup_bot(self, ctx: commands.Context, number: int, delete_pinned: bool = False): """Clean up command messages and messages from the bot.""" channel = ctx.channel author = ctx.message.author if number > 100: cont = await self.check_100_plus(ctx, number) if not cont: return prefixes = await self.bot.get_prefix( ctx.message) # This returns all server prefixes if isinstance(prefixes, str): prefixes = [prefixes] # In case some idiot sets a null prefix if "" in prefixes: prefixes.remove("") cc_cog = self.bot.get_cog("CustomCommands") if cc_cog is not None: command_names: Set[str] = await cc_cog.get_command_names(ctx.guild) is_cc = lambda name: name in command_names else: is_cc = lambda name: False alias_cog = self.bot.get_cog("Alias") if alias_cog is not None: alias_names: Set[str] = ( set((a.name for a in await alias_cog.unloaded_global_aliases())) | set(a.name for a in await alias_cog.unloaded_aliases(ctx.guild))) is_alias = lambda name: name in alias_names else: is_alias = lambda name: False bot_id = self.bot.user.id def check(m): if m.author.id == bot_id: return True elif m == ctx.message: return True p = discord.utils.find(m.content.startswith, prefixes) if p and len(p) > 0: cmd_name = m.content[len(p):].split(" ")[0] return (bool(self.bot.get_command(cmd_name)) or is_alias(cmd_name) or is_cc(cmd_name)) return False to_delete = await self.get_messages_for_deletion( channel=channel, number=number, check=check, before=ctx.message, delete_pinned=delete_pinned, ) to_delete.append(ctx.message) reason = ("{}({}) deleted {} " " command messages in channel {}." "".format(author.name, author.id, len(to_delete), channel.name)) log.info(reason) await mass_purge(to_delete, channel)
async def cleanup_self( self, ctx: commands.Context, number: int, match_pattern: str = None, delete_pinned: bool = False, ): """Clean up messages owned by the bot. By default, all messages are cleaned. If a third argument is specified, it is used for pattern matching: If it begins with r( and ends with ), then it is interpreted as a regex, and messages that match it are deleted. Otherwise, it is used in a simple substring test. Some helpful regex flags to include in your pattern: Dots match newlines: (?s); Ignore case: (?i); Both: (?si) """ channel = ctx.channel author = ctx.message.author if number > 100: cont = await self.check_100_plus(ctx, number) if not cont: return # You can always delete your own messages, this is needed to purge can_mass_purge = False if type(author) is discord.Member: me = ctx.guild.me can_mass_purge = channel.permissions_for(me).manage_messages use_re = match_pattern and match_pattern.startswith("r(") and match_pattern.endswith(")") if use_re: match_pattern = match_pattern[1:] # strip 'r' match_re = re.compile(match_pattern) def content_match(c): return bool(match_re.match(c)) elif match_pattern: def content_match(c): return match_pattern in c else: def content_match(_): return True def check(m): if m.author.id != self.bot.user.id: return False elif content_match(m.content): return True return False to_delete = await self.get_messages_for_deletion( channel=channel, number=number, check=check, before=ctx.message, delete_pinned=delete_pinned, ) if ctx.guild: channel_name = "channel " + channel.name else: channel_name = str(channel) reason = ( "{}({}) deleted {} messages " "sent by the bot in {}." "".format(author.name, author.id, len(to_delete), channel_name) ) log.info(reason) if can_mass_purge: await mass_purge(to_delete, channel) else: await slow_deletion(to_delete)
async def cleanup_bot(self, ctx: commands.Context, number: int, delete_pinned: bool = False): """Clean up command messages and messages from the bot.""" channel = ctx.channel author = ctx.message.author if number > 100: cont = await self.check_100_plus(ctx, number) if not cont: return prefixes = await self.bot.get_prefix(ctx.message) # This returns all server prefixes if isinstance(prefixes, str): prefixes = [prefixes] # In case some idiot sets a null prefix if "" in prefixes: prefixes.remove("") cc_cog = self.bot.get_cog("CustomCommands") if cc_cog is not None: command_names: Set[str] = await cc_cog.get_command_names(ctx.guild) is_cc = lambda name: name in command_names else: is_cc = lambda name: False alias_cog = self.bot.get_cog("Alias") if alias_cog is not None: alias_names: Set[str] = ( set((a.name for a in await alias_cog.unloaded_global_aliases())) | set(a.name for a in await alias_cog.unloaded_aliases(ctx.guild)) ) is_alias = lambda name: name in alias_names else: is_alias = lambda name: False bot_id = self.bot.user.id def check(m): if m.author.id == bot_id: return True elif m == ctx.message: return True p = discord.utils.find(m.content.startswith, prefixes) if p and len(p) > 0: cmd_name = m.content[len(p) :].split(" ")[0] return ( bool(self.bot.get_command(cmd_name)) or is_alias(cmd_name) or is_cc(cmd_name) ) return False to_delete = await self.get_messages_for_deletion( channel=channel, number=number, check=check, before=ctx.message, delete_pinned=delete_pinned, ) to_delete.append(ctx.message) reason = ( "{}({}) deleted {} " " command messages in channel {}." "".format(author.name, author.id, len(to_delete), channel.name) ) log.info(reason) await mass_purge(to_delete, channel)