Anti spam code keeps spamming to the bot too - python

This is an anti spam code to prevent spams and stuff.
time_window_milliseconds = 5000
max_msg_per_window = 5
author_msg_times = {}
# Struct:
# {
# "<author_id>": ["<msg_time", "<msg_time>", ...],
# "<author_id>": ["<msg_time"],
# }
#client.event
async def on_message(message):
global author_msg_counts
author_id = message.author.id
# Get current epoch time in milliseconds
curr_time = datetime.now().timestamp() * 1000
# Make empty list for author id, if it does not exist
if not author_msg_times.get(author_id, False):
author_msg_times[author_id] = []
# Append the time of this message to the users list of message times
author_msg_times[author_id].append(curr_time)
# Find the beginning of our time window.
expr_time = curr_time - time_window_milliseconds
# Find message times which occurred before the start of our window
expired_msgs = [
msg_time for msg_time in author_msg_times[author_id]
if msg_time < expr_time
]
# Remove all the expired messages times from our list
for msg_time in expired_msgs:
author_msg_times[author_id].remove(msg_time)
# ^ note: we probably need to use a mutex here. Multiple threads
# might be trying to update this at the same time. Not sure though.
if len(author_msg_times[author_id]) > max_msg_per_window:
await message.channel.send(f"{message.author.mention} stop spamming or i will mute you 😡")
await asyncio.sleep(4)
await message.channel.send(f"{message.author.mention} stop spamming or i will mute you 😡")
muted = discord.utils.get(message.guild.roles, name="Muted")
if not muted:
muted = await message.guild.create_role(name="Muted")
await message.author.send(f"You have been muted in {message.guild.name} for spamming | You'll be unmuted in 10 minutes.")
await message.author.add_roles(muted)
await message.channel.send(f"{message.author.mention} have been muted for 10 minutes.")
await asyncio.sleep(600)
await message.channel.send(f"{message.author.mention} have been unmuted | Reason: Time is over. ")
await message.author.remove_roles(muted)
await message.author.send(f"You have been unmuted from {message.guild.name}")
Hey guys, I'm getting an error here. It works OK, but when someone keeps spamming, the bot keeps spamming, and it becomes a mess. After about a minute, the bot keeps spamming, so stop spamming or I'll mute you.

You need to exclude your own bots messages in the event. So just this should work:
#client.event
async def on_message(message):
if message.author == client.user:
return
#rest of your code

Related

Python discord bot not respoding to on_message event

I'm trying to make a discord bot but the bot is not responding to any of my commands.
He is writing the command when going online but nothing more.
I have given him every permission and intent but it did not help.
import discord
import time
intents = discord.Intents.default()
intents.members = True
client = discord.Client(intents=intents)
# Dictionary to store the brake times for each user
brb_times = {}
#client.event
async def on_message(message):
# Only process messages from other users, not the bot itself
if message.author == client.user:
return
if message.content.startswith("!brb 5"):
brb_times[message.author.name] = time.time() + 5 * 60
await message.channel.send(f"{message.author.mention} has taken a 5-minute brake.")
elif message.content.startswith("!brb 10"):
brb_times[message.author.name] = time.time() + 10 * 60
await message.channel.send(f"{message.author.mention} has taken a 10-minute brake.")
elif message.content.startswith("!brb 15"):
brb_times[message.author.name] = time.time() + 15 * 60
await message.channel.send(f"{message.author.mention} has taken a 15-minute brake.")
elif message.content.startswith("!back"):
if message.author.name in brb_times:
brake_time = brb_times[message.author.name]
del brb_times[message.author.name]
elapsed_time = time.time() - brake_time
if elapsed_time > 0:
await message.channel.send(f"{message.author.mention} is back, but was late by {int(elapsed_time)} seconds.")
else:
await message.channel.send(f"{message.author.mention} is back.")
else:
await message.channel.send(f"{message.author.mention} was not on a brake.")
#client.event
async def on_ready():
print("Bot is ready!")
await client.get_channel(CENSORED).send("Bot is ready to track breaks!")
client.run("CENSORED")
You need message_content to be True in intents.

Discord.py counts down until adding Role A when a member sends a message while having Role B. Role A gets added even if role B has been taken away

Currently when someone sends a message and has the "Hunger" role, the bot gives them a countdown role (to stop the counting to repeat) and counts 60 seconds, then gives them the "dead" role. However, after the timer is done, it gives the "dead" role even if "hunger" has been taken away which I only want to happen if the user still has "hunger".
#client.event
async def on_message(message):
Hunger = message.guild.get_role(957207332134223892)
Counting = message.guild.get_role(957525791426637834)
Dead = message.guild.get_role(852087847917715457)
if Hunger in message.author.roles:
if Counting not in message.author.roles:
if Dead not in message.author.roles:
await message.author.add_roles(Counting)
time.sleep(60)
if Hunger in message.author.roles:
await message.author.add_roles(Dead)
await message.author.remove_roles(Counting)
This seems to work. Use asyncio.sleep() instead:
import asyncio
#bot.command()
async def role(ctx):
Hunger = ctx.guild.get_role(957207332134223892)
Counting = ctx.guild.get_role(957525791426637834)
Dead = ctx.guild.get_role(852087847917715457)
if Hunger in ctx.author.roles:
if Counting not in ctx.author.roles:
if Dead not in ctx.author.roles:
await ctx.author.add_roles(Counting)
await asyncio.sleep(60)
await ctx.author.remove_roles(Counting)
if Hunger in ctx.author.roles:
await ctx.author.add_roles(Dead)

How do I check which reaction inthe message is higher in Discord.py?

So basicly, I'm creating a command that let you vote for something and after 5 min it will check which is higher.
But the problem is I don't know how to do that.
Here is my code so far:
#client.command()
async def strongy_boi(ctx, boi):
if boi == "copper-golem-allay":
mess = await ctx.send(":heart: = copper golem :blue_heart: = allay")
await mess.add_reaction('❤️')
await mess.add_reaction('💙')
await asyncio.sleep(5)
#do code that check which is higher
One way you can do this is to access the message reactions through discord.Message.reactions and iterate through them, checking the discord.Reaction.count and comparing with the current highest. To check for reactions, however, a message needs to be cached, which can be done through await fetch_message(). Do view the revised code and further explanations below.
#client.command()
async def strongy_boi(ctx, boi):
if boi == "copper-golem-allay":
mess = await ctx.send("❤️ = copper golem 💙 = allay")
await mess.add_reaction('❤️')
await mess.add_reaction('💙')
await asyncio.sleep(5)
# new code starts here #
msg = await ctx.channel.fetch_message(mess.id) # 'Cache' the message
# create variables to save the highest reactions
highest_reaction = ""
highest_reaction_number = 0
# msg.reactions format:
# [<Reaction emoji='❤️' me=True count=2>, <Reaction emoji='💙' me=True count=1>]
for reaction in msg.reactions: # iterate through every reaction in the message
if (reaction.count-1) > highest_reaction_number:
# (reaction.count-1) discounts the bot's reaction
highest_reaction = reaction.emoji
highest_reaction_count = reaction.count-1
await ctx.send(f"{highest_reaction} wins with {highest_reaction_count} votes!")
Other Links:
Count reactions on a message - Stackoverflow
How do I count reactions on a message in discord py? - Stackoverflow
Reactions counting - Stackoverflow
Get a List of Reactions on a Message - Stackoverflow

Mute and delete messages antispam discord.py

async def on_message(message: object):
counter = 0
with open("spam_detect.txt", "r+") as file:
for lines in file:
if lines.strip("\n") == str(message.author.id):
counter += 1
file.writelines(f"{str(message.author.id)}\n")
if counter > 5 and not message.author.guild_permissions.administrator:
await message.author.send("Ai primit kick pentru spam. Poti intra in `60` secunde.")
await asyncio.sleep(2)
await message.guild.ban(message.author, reason="spam")
await message.channel.send(f"{message.author} a primit kick pentru `spam`.")
await asyncio.sleep(60)
await message.guild.unban(message.author)
Does anyone know how instead of banning and unbanning someone i can give them the Muted role and delete all messages in the past hour ?
Yes, we simply have to get their messages and delete it.
from datetime import datetime
await message.channel.purge(after=datetime.now() - timedelta(hours=1), check = lambda x: x.author.id == message.author.id, oldest_first=False) #purges the channel
muted_role = discord.utils.get(guild.roles, name='Muted')
await message.author.add_roles(muted_role)
await message.channel.send('muted spammer and deleted messages')
the check parameter makes it delete only the author's messages.

Make bot disconnect if it's alone in a voice channel discord.py

Is there any way to disconnect the bot if it's alone on a voice channel? Is there any event that triggers each time a person leaves the vc or something similar that would do the job?
I don't know the voice channels well but you can check the member count with VoiceChannel.members and make a task loop like
async def check():
# define the voice channel
member_count = len(voice_channel.members)
if member_count == 1:
# leave the channel
await asyncio.sleep(30)
client.loop.create_task(check())
There might be better answers but this can also solve your problem.
To someone who might be having the same issue and want an answer
GUILD_VC_TIMER = {}
# this event runs when user leave / join / defen / mute
#bot.event
async def on_voice_state_update(member, before, after):
# if event is triggered by the bot? return
if member.id == bot.user.id:
return
# when before.channel != None that means user has left a channel
if before.channel != None:
voice = discord.utils.get(bot.voice_clients , channel__guild__id = before.channel.guild.id)
# voice is voiceClient and if it's none? that means the bot is not in an y VC of the Guild that triggerd this event
if voice == None:
return
# if VC left by the user is not equal to the VC that bot is in? then return
if voice.channel.id != before.channel.id:
return
# if VC has only 1 member (including the bot)
if len(voice.channel.members) <= 1:
GUILD_VC_TIMER[before.channel.guild.id] = 0
while True:
print("Time" , str(GUILD_VC_TIMER[before.channel.guild.id]) , "Total Members" , str(len(voice.channel.members)))
await asyncio.sleep(1)
GUILD_VC_TIMER[before.channel.guild.id] += 1
# if vc has more than 1 member or bot is already disconnectd ? break
if len(voice.channel.members) >= 2 or not voice.is_connected():
break
# if bot has been alone in the VC for more than 60 seconds ? disconnect
if GUILD_VC_TIMER[before.channel.guild.id] >= 60:
await voice.disconnect()
return

Categories

Resources