Discord.py Anti-spam ignore channel command broken - python

Hello I am trying to make an ANTI SPAM bot to work on catching spammers and kicking the from the server. My problem though with the code is that it ignores all channels in the guild and not the channels in the json file.
Here is my code can you please take a look and update me on what I did wrong. Thanks
#client.listen()
async def on_message(message):
counter = 0
with open("spam-bank.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")
try:
with open("channels.json", "r") as r:
j = json.load(r)
all_channels = j["channels"]
return all_channels
if counter > 3:
await message.channel.send(f'{message.author} has been kicked for spamming')
await message.guild.kick(message.author,reason="Caught by Anti-Spam for Spamming")
print(f'{message.author} was kicked')
await asyncio.sleep(2)
except:
return
#client.command()
async def ignore(ctx, channel_):
def add_channel(channel, file="channels.json"):
with open(file, "r+") as fw:
j = json.load(fw)
j["channels"].append(channel)
with open(file, "w+") as wp:
wp.write(json.dumps(j))
try:
with open("channels.json", "r"):
pass
except:
with open("channels.json", "w+") as wp:
wp.write('{"channels" : []}')
finally:
add_channel(channel_)
await ctx.send("Done!")

The issue is here:
with open("channels.json", "r") as r:
j = json.load(r)
all_channels = j["channels"]
return all_channels
When execution hits return all_channels, the function ends, and all_channels is returned. No code after that will be reached.
Instead, you need to write code to check if the channel the message was sent in is contained in all_channels and return/skip only in that case.
One simple way to figure this out in the future is to add lots of temporary print statements, and trace through the function by following the print statements.
with open("channels.json", "r") as r:
j = json.load(r)
print("loaded json from file")
all_channels = j["channels"]
print(f"extracted channels from json: {all_channels}")
return all_channels
print(f"checking counter: {counter}")
if counter > 3:
print("user has sent more than 3 messages. Kicking..")
await message.channel.send(f'{message.author} has been kicked for spamming')
await message.guild.kick(message.author,reason="Caught by Anti-Spam for Spamming")
print(f'{message.author} was kicked')
await asyncio.sleep(2)
You'll get an output like
loaded json from file
extracted channels from json: [list]
And from that, you can easily tell that something's going wrong between that print statement and the next one, because checking counter: [number] isn't getting printed.

Related

discord py how to fetch messages with jump_url and reactions attributes

I'm trying to make a bot that would autoreact, check the amount of reactions on the messages in a channel, make a link to the message and send it on a moderation channel if it got 2 or more reactions, then log it's jump url in bot's directory. I cant find a way to fetch all the messages with jump_url and reactions attributes. im feeling super lost so i'll put the code here
async def on_message(message):
if message.channel.id == 828579458167996420:
channel = client.get_channel(828579458167996420)
if message.attachments or "http" in message.content:
await message.add_reaction("<:MashaUpset:828589397074116709>")
x = int
messages = await channel.history(limit=21).flatten()
f = open("message log.txt","r")
readfile = f.read()
f.close()
if str(messages.jump_url) not in readfile:
if messages.reactions[0].count >= 2:
x = messages.reactions[0].count - 1
link = messages.jump_url
channel = client.get_channel(892065611876823100)
await channel.send("this post was liked "+ str(x) + " times! "+ str(link))
f = open("message log.txt", "a")
f.write("\n" + str(messages.jump_url))
f.close()
im a beginner, so sorry for the mess i've made
Edit: can't fetch jump_url, so instead fetching for message.id
Ok I found it. thx to Dominik for help
Changes I've done
I've separated the script into 2 parts, an on_message and a #tasks.loop
Added a for x loop
Added an await channel.fetch_message(x.id) in the loop
Fetched for message.id rather than jump_url
Added if statement to check if the message has reactions
#client.event
async def on_message(message):
if message.channel.id == 828579458167996420:
if message.attachments or "http" in message.content:
await message.add_reaction("<:MashaUpset:828589397074116709>")
#tasks.loop(minutes=2)
async def check():
channel = client.get_channel(828579458167996420)
messages = await channel.history(limit=30).flatten()
await asyncio.sleep(3)
f = open("message log.txt","r")
readfile = f.read()
f.close()
for message in messages:
channel = client.get_channel(828579458167996420)
message = await channel.fetch_message(message.id)
if str(message.id) not in readfile:
if message.reactions:
if message.reactions[0].count >= 2:
x = message.reactions[0].count - 1
link = message.jump_url
channel = client.get_channel(892065611876823100)
await channel.send("this post was liked "+ str(x) + " times! "+ str(link))
f = open("message log.txt", "a")
f.write("\n" + str(message.id))
f.close()
#check.before_loop
async def before():
await client.wait_until_ready()
check.start()

How do I set the channel_ id to a function in discord.py

def get_channel_id(client, message):
with open('./json/welcome.json', 'r') as f:
channel_id = json.load(f)
return channel_id[str(message.guild.id)]
#client.event
async def on_member_join(member):
embed = discord.Embed(colour=0x767429, description=f"Welcome to my server! You are the {len(list(member.guild.members))}th member ")
embed.set_thumbnail(url=f" {member.avatar_url} ")
embed.set_author(name=f" {member.name} ", icon_url=f" {member.avatar_url} ")
embed.set_footer(text=f"{ member.guild }", icon_url=f" {member.guild.icon_url} ")
embed.timestamp = datetime.datetime.utcnow()
channel = client.get_channel(id=get_channel_id)
await channel.send(embed=embed)
#client.command()
async def welcomechannel(ctx, channel_id):
with open('./json/welcome.json', 'r') as f:
id = json.load(f)
id[str(ctx.guild.id)] = channel_id
with open('./json/welcome.json', 'w') as f:
json.dump(id, f, indent=4)
await ctx.send(f'Welcome channel changed to {channel_id}')
I'd like to have the get_channel_idfunction be the ID of the channel = client.get_channel(id=get_channel_id) but everytime I run it i get the error AttributeError: 'NoneType' object has no attribute 'send'. Can someone please help me
You can simplify the code quite a bit. As mentioned in my comment, you also need to open the JSON when a new user enters the server.
Your own function above is completely redundant and not needed.
I also once changed your welcomechannel command a bit because you don't get far with channel_id, you can use channel: discord.TextChannel instead and it comes out the same.
Here is the command for now:
#client.command()
async def welcomechannel(ctx, channel: discord.TextChannel): # We use discord.TextChannel
with open('./json/welcome.json', 'r') as f:
id = json.load(f)
id[str(ctx.guild.id)] = channel.id # Saving JUST the ID, you also had <#ID> in it
with open('./json/welcome.json', 'w') as f:
json.dump(id, f, indent=4)
await ctx.send(f'Welcome channel changed to `{channel}`')
And now to check the channel. For that we open the JSON in the same way as we did with the command:
#client.event
async def on_member_join(member):
with open('./json/welcome.json', 'r') as f:
wchannel = json.load(f) # Define our channel
try:
if wchannel: # If a channel is set for the server
wchannelsend = member.guild.get_channel(wchannel[str(member.guild.id)]) # Get the channel from the JSON
embed = discord.Embed(color=0x767429,
description=f"Welcome to my server! You are the {len(list(member.guild.members))}th member ")
embed.set_thumbnail(url=f"{member.avatar_url} ")
embed.set_author(name=f"{member.name} ", icon_url=f"{member.avatar_url} ")
embed.set_footer(text=f"{member.guild}", icon_url=f"{member.guild.icon_url} ")
embed.timestamp = datetime.datetime.utcnow()
await wchannelsend.send(embed=embed) # Send the embed to the channel
else:
return # If no channel was set, nothing will happen
except:
return

How to make a sub command without trigger discord.ext.commands.errors.MissingRequiredArgument?

(This is my first post by the way <3)
I am making a discord.py bot and I want a command that will either list warnings (warnings list ) for a user, clear warnings for a user (warnings clear ) or give a help message for the command (anything that does not fit the other two commands)!
Here is the code:
#commands.command(name="warnings")
async def warnings(self, ctx, usage, user):
if usage == "clear":
f = open(user + ".txt", "w")
f.write("")
f.close()
embed = discord.Embed(title="Warnings removed", description=f"I have removed all warnings for <#!{user}>", colour=discord.Colour.green())
await ctx.channel.send(embed=embed)
elif usage == "list":
try:
f = open(user + ".txt", "r")
readResult = f.read()
if readResult.startswith("Reason: "):
embed = discord.Embed(title="Warnings for: <#!" + user + ">", description=readResult, colour=discord.Colour.red())
await ctx.channel.send(embed=embed)
else:
embed = discord.Embed(title="This user has no warnings", colour=discord.Colour.green())
await ctx.channel.send(embed=embed)
except:
embed = discord.Embed(title="This user has no warnings", colour=discord.Colour.green())
await ctx.channel.send(embed=embed)
I have tried an if statement and using #warnings.error but it has not worked, I have also searched the previous questions with this same error message but they are not quite the same! :(
By the way the code itself isnt the problem :)
What I expect:
!warnings
>[Something help info.]
What I get:
raise MissingRequiredArgument(param)
discord.ext.commands.errors.MissingRequiredArgument: usage is a required argument that is missing.
use param=None to do a sub command, maybe you can search how to make a custom help, that'll help you.
#commands.command(name="warnings")
async def warnings(self, ctx, usage=None, user=None):
if usage is None:
pass # do something here
elif usage == "clear":
f = open(user + ".txt", "w")
...

keep message count offline discord.py

I have a bot that counts when the nword is said, but when the bot goes offline the count resets
here is my code(the nword is being censored)
bot.softn = 0
bot.hardn = 0
#bot.event
async def on_message(message):
user = message.author
if message.content == "nibba":
embed=discord.Embed(title="racist", description=f"{user} said the N-word! \n racist!", color=0xb1f1c0)
await message.channel.send(embed=embed)
bot.softn += 1
elif message.content == "nibberr":
embed=discord.Embed(title="racist", description=f"{user} said the N-word! \n racist!", color=0xb1f1c0)
await message.channel.send(embed=embed)
bot.softn += 1
bot.hardn += 1
await bot.process_commands(message)
#bot.command()
async def racist(ctx):
embed=discord.Embed(title="Rascist Counter", description=f"N-word has been said {ctx.bot.softn} times!\n\nand of which the hard-R has been said {ctx.bot.hardn} times", color=0xefe0b4)
embed.add_field(name="Conclusion", value="The n-word is overrated. Get a better vocabulary", inline=True)
await ctx.send(embed=embed)
how can I have the counter not be reset?
I found a pretty good solution based on different contributions here, so you should take a closer look next time. You have to save the counter in a file, otherwise it will be lost, no matter what you do.
You mainly need 2 functions:
def load_counters():
with open('counter.json', 'r') as f:
counters = json.load(f)
return counters
def save_counters(counters):
with open('counter.json', 'w') as f:
json.dump(counters, f)
We use a JSON file called counter in this case. Here we load and save the JSON as a file.
dump means that we update the counter itself.
If you now want to listen to all the messages and save your word in this file you can use the following on_message event:
#bot.event()
async def on_message(message):
if "YourWord" in message.content:
counters = load_counters() # First load the file
counters["YourWord"] += 1 # Count up
save_counters(counters) # Save the count
How do we now get the count out of the file?
To read out the file we first have to open it, before we use it in a command:
with open('counter.json', 'r') as f:
counters1 = json.load(f) # Open and load the file
Now we can use counter1 to display the counter with:
f"{counters1['YourWord']}"
I would suggest to read the docs again and also have a look at how to use JSON files in Python

Replacing a line in a file with Python doesn't work like it's supposed to

I'm creating a discord bot and tryying to save stats about every user and their messages sent but it's not working. This is what I have:
async def update_stats():
await client.wait_until_ready()
global messages, author
data = []
if author != 0:
try:
with open("stats.txt", "r") as f:
data = f.readlines()
for item in data:
author2, messages2 = item.split(":")
print(author2, messages2)
index = data.index(item)
if author == author2:
with open("stats.txt", "w") as f1:
data.pop(index)
novi_stat = f"""{author}:{int(messages) + int(messages2)}\n"""
data.insert(index, novi_stat)
str = ''.join(data)
f1.write(str)
else:
with open("stats.txt", "w") as f2:
data.append(f"""{author}:{messages}\n""")
str = ''.join(data)
f2.write(str)
await asyncio.sleep(5)
except Exception as e:
print(e)
await asyncio.sleep(5)
And this is the content of the text file it loads and is supposed to change when number of messages changes:
DrDEagle#4984:100
kreten:123
This is what I get when running the code:
DrDEagle#4984:100
kreten:123
:0
It is supposed to change the number from 100 to 101 if I send one message, but instead it writes a new line which doesn't even contain the right data, what am I doing wrong?
EDIT: After an hour of editing and rewriting the code, I did this and it works.
import discord
import random
import aiohttp
import asyncio
import json
import datetime
client = discord.Client()
sentdex_guild = client.get_guild(No, No!) # I didn't post the code...
author = ''
messages = 0
#client.event
async def on_message(message):
global author, messages
author = message.author.name
messages += 1
authorsInFile = []
f = open("stats.txt", 'r')
data = f.readlines()
for item in data:
author2, messages2 = item.split(":")
authorsInFile.append(author2)
print(author2, messages2)
if author in authorsInFile:
index = authorsInFile.index(author)
else:
pass
if author2 == author:
f1 = open("stats.txt", "w")
print(author)
data.pop(index)
novi_stat = f"""{author}:{int(messages2) + 1}\n"""
data.insert(index, novi_stat)
str = ''.join(data)
f1.write(str)
f1.close()
f.close()
else:
f2 = open("stats.txt", "w")
data.append(f"""{author}:{messages}\n""")
str = ''.join(data)
f2.write(str)
f2.close()
f.close()
await asyncio.sleep(5)
with open('log.txt', 'a') as f:
f.write(f"""{datetime.datetime.now()} | {message.author} je rekao: {message.content}\n""")
if message.content == "!bok":
await message.channel.send("Pozdrav!")
elif message.content == "!korisnici":
online = 0
idle = 0
offline = 0
for m in sentdex_guild.members:
if str(m.status) == "online":
online += 1
if str(m.status) == "offline":
offline += 1
else:
idle += 1
await message.channel.send(f"""Broj korisnika: {online+offline - 1}\nˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇˇ\nOnline korisnika: {online - 1}\nOffline korisnika: {offline}\n^^^^^^^^^^^^^^^^^^^^^^^^""") # printa broj korisnika, ali ne broji sebe
elif message.content == "!ping":
latency = client.latency
await message.channel.send(f"""Moj ping iznosi {round(latency, 6)}ms""")
elif message.content == "!yacketty":
await message.channel.send("Dostupne komande su: !ping, !bok, !korisnici, !bitcoin...")
elif message.content == "!bitcoin":
url = 'https://api.coindesk.com/v1/bpi/currentprice/BTC.json'
async with aiohttp.ClientSession() as session: # Async HTTP request
raw_response = await session.get(url)
response = await raw_response.text()
response = json.loads(response)
await message.channel.send("Cijena bitcoina: $" + response['bpi']['USD']['rate'])
elif "!8ball" in message.content:
moguci_odgovori = [
'Nema jebene šanse',
'Možda, ali samo možda',
'Ahhh, 50-50',
'Vrlo moguće',
'Apsolutno da'
]
await message.channel.send(random.choice(moguci_odgovori) + ", " + message.author.mention)
#client.event
async def welcome(member):
for channel in member.server.channels:
if str(channel) == "general":
await client.send_message(f"""{member.mention}, dobrodošao na server!""")
client.run("I'm not showing you this hehe")
I don't see anywhere that you set either author or messages. You have them set as globals, so I assume you're setting them before calling this function. If author is an empty string, and messages is 0, then the output you are getting is just what I would expect from your code.
Since there is not yet an author named "", it appends an entry for that author to the file that is the empty author name, a colon, and the 0 that is the value of message.
Note that your first if test would succeed and the if block entered in this proposed case, as "" != 0 is True.
Another observation...you're reading in multiple existing authors, but you seem to be only comparing the passed in author against the last author read in from the file. I'm assuming that's not what you want...you probably want to be comparing each author you read in against the passed in author in the loop that is processing each line of the file.

Categories

Resources