How to fix discord.py not sending an embed? - discord.py

I have been creating a discord.py bot and have run into the issue of my discord bot not being able to send embeds there are no errors in the console the command was working before:
#client.command()
async def usercheck(ctx, username, number):
collection.update_one({"_id":ctx.guild.id},{"$set": {f'Userid{number}': username}})
for x in collection.find():
if x["_id"] == ctx.guild.id:
variable = x["Pop"]
variable2 = x[f'Userid{number}']
response = requests.get('https://api.battlemetrics.com/players/' + variable2 + '?fields[server]=name&filter[servers]=' + variable + '&include=server')
pass_times = response.json()
Player_id = pass_times['data']['attributes']['id']
Player_name = pass_times['data']['attributes']['name']
Server_name = pass_times['included'][0]['attributes']['name']
Player_online = pass_times['included'][0]['meta']['online']
Player_id = str(Player_id)
url = 'https://www.battlemetrics.com/players/' + Player_id
embed = discord.Embed(title=Player_name, description=url, color=0x1eff00)
embed.add_field(name="Status", value="Online: " + Player_online, inline=False)
embed.add_field(name="Server", value=Server_name, inline=False)
await ctx.send(embed=embed)

Since this line: Player_online = pass_times['included'][0]['meta']['online'] returns a boolean, you need to cast it to a string to send messages, this should fix your error:
embed.add_field(name="Status", value="Online: " + str(Player_online), inline=False)
or:
Player_online = str(pass_times['included'][0]['meta']['online'])

Related

Check which reaction a user picked [Discord.py]

This should be fairly simple and I've been trying what I've googled but no luck. All I want to do is send a message regarding which emoji had more reactions. But nothing is being sent out.
#bot.event
async def on_message(message):
if 'aoe2' in message.content and message.channel.id == 1048127088688889866:
BlueEmbed = discord.Embed(title='AOE Lobby',
description='**Lobby Link:** ' + '<' +
str(message.content) + '>',
colour=discord.Colour.blue())
message = await message.channel.send(embed=BlueEmbed)
await message.add_reaction('❤️')
await message.add_reaction('💙')
msg = await message.channel.fetch_message(message.id)
highest_reaction = ""
highest_reaction_number = 0
for reaction in msg.reactions:
if reaction.count - 1 > highest_reaction_number:
highest_reaction = reaction.emoji
highest_reaction_count = reaction.count - 1
await message.channel.send(f"{highest_reaction} wins with {highest_reaction_count} votes!")
the issue seems to be the program not waiting to check for votes, but rather executing the code instantly. Ignoring future reactions added. Not sure on a work around at this time. Seems I may need some sort of delay before running the if statement.
Use asyncio.sleep()
#bot.event
async def on_message(message):
if 'aoe2' in message.content and message.channel.id == 1048127088688889866:
BlueEmbed = discord.Embed(title='AOE Lobby',
description='**Lobby Link:** ' + '<' +
str(message.content) + '>',
colour=discord.Colour.blue())
message = await message.channel.send(embed=BlueEmbed)
await message.add_reaction('❤️')
await message.add_reaction('💙')
await asyncio.sleep(5) #however long u want in seconds
msg = await message.channel.fetch_message(message.id)
highest_reaction = ""
highest_reaction_number = 0
for reaction in msg.reactions:
if reaction.count - 1 > highest_reaction_number:
highest_reaction = reaction.emoji
highest_reaction_count = reaction.count - 1
await message.channel.send(f"{highest_reaction} wins with {highest_reaction_count} votes!")
or you can have another phrase trigger it
#bot.event
async def on_message(message):
global messageid
if 'aoe2' in message.content and message.channel.id == 1048127088688889866:
BlueEmbed = discord.Embed(title='AOE Lobby',
description='**Lobby Link:** ' + '<' +
str(message.content) + '>',
colour=discord.Colour.blue())
message = await message.channel.send(embed=BlueEmbed)
await message.add_reaction('❤️')
await message.add_reaction('💙')
messageid = message.id
if "trigger" in message.content and message.channel.id == 1048127088688889866::
msg = await message.channel.fetch_message(messageid)
highest_reaction = ""
highest_reaction_number = 0
for reaction in msg.reactions:
if reaction.count - 1 > highest_reaction_number:
highest_reaction = reaction.emoji
highest_reaction_count = reaction.count - 1
await message.channel.send(f"{highest_reaction} wins with {highest_reaction_count} votes!")

Word limit in an embed description

I want to make that when the description of the embed exceeds the word limit it continues in another separate embed but that the previous embed ends with 3 dots (...) eliminating a small part of the message and following it in the other embed, at the moment this is the code I have:
#commands.command(aliases=["pj"])
async def personaje(self, ctx, personaje=None, member: discord.Member=None):
if personaje is None:
await ctx.send(":x: Debes proporcionar la id del personaje que quieres visualizar")
else:
if member is None:
member = ctx.author
if os.path.exists("json/Roleplay/Personajes/{member}/{idpersonaje}.json".format(member=member.id, idpersonaje=personaje)):
with open("json/Roleplay/Personajes/{member}/{idpersonaje}.json".format(member=member.id, idpersonaje=personaje), 'r') as f:
data = json.load(f)
Nombre = data["Nombre"]
Historia = data["Historia"]
color = data["Color"]
personalizado = data["Personalizado"]
text = ""
text = "".join(f"\n**{key}:** {value}" for key, value in personalizado.items())
color = int(color, 16)
timestamp = datetime.datetime.now()
prueba = f"**{Nombre} {text}\n\n**Historia:**\n {Historia}"
if len(prueba) < 2000:
embed=discord.Embed(description=prueba, color=color)
embed.set_author(name=ctx.author, icon_url=ctx.author.avatar_url)
embed.timestamp = timestamp
await ctx.send(embed=embed)
else:
embed=discord.Embed(description=prueba[:-3] + "...", color=color)
embed.set_author(name=ctx.author, icon_url=ctx.author.avatar_url)
embed.timestamp = timestamp
await ctx.send(embed=embed)
else:
await ctx.send(":x: Este personaje no existe")
return
Example of what I want to do (obviously with a longer text that exceeds 2000 words):
https://imgur.com/zytqLKm
Best method is making a function to split the data every n char.
Making fields with name of empty line might be better then using new embed.
Keep in mind don't split at 2000 exactly because you have ...
def split_length(data: str, n: int):
'''Splits the data given at each given n'''
out_data = []
for i in range(0, len(data), n):
out_data.append(data[i:i+n])
return out_data
#bot.command()
async def longtext(ctx):
embed = discord.Embed(title='Example of long text split')
long_text = 'qwerty'
field_values = split_length(data=long_text, n=2)
for value in field_values:
# "\u200b" is just an empty line
embed.add_field(name="\u200b", value=f"{value} ...", inline=True)
await ctx.send(embed=embed)

I'm having a problem with my modmail bot code that was written my discord.py

So, I'm making a modmail bot for my discord server. But when I run, the bot can connect but when I send a test messange in the bot DM, I receive this error: AttributeError: 'NoneType' object has no attribute 'send'.
I'm using python 3.9.1 on Arch Linux. Here is my code:
import discord
from discord.ext.commands import Bot
from discord.ext import commands
import asyncio
client = commands.Bot(command_prefix="!")
#client.event
async def on_ready():
await client.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name='for moderation mail'))
print("Thunderbird is ready")
#client.event
async def on_message(message):
empty_array = []
modmail_channel = discord.utils.get(client.get_all_channels(), name="modmail-box")
if message.author == client.user:
return
if str(message.channel.type) == "private":
if message.attachments != empty_array:
files = message.attachments
await modmail_channel.send("<#" + message.author.id + ">: ")
for file in files:
await modmail_channel.send(file.url)
else:
await modmail_channel.send("<#" + str(message.author.id) + ">: " + message.content)
elif str(message.channel) == "modmail" and message.content.startswith("<"):
member_object = message.mentions[0]
if message.attachments != empty_array:
files = message.attachments
await member_object.send("**[MOD]** " + "**" + message.author.display_name + "**: ")
for file in files:
await member_object.send(file.url)
else:
index = message.content.index(" ")
string = message.content
mod_message = string[index:]
await member_object.send("**[MOD]** " + "**" + message.author.display_name + "**: " + mod_message)
client.run('No leaking here')
I am assuming that the error is on this line:
await member_object.send("**[MOD]** " + "**" + message.author.display_name + "**: ")
and member_object is coming from this block:
elif str(message.channel) == "modmail" and message.content.startswith("<"):
member_object = message.mentions[0]
if message.attachments != empty_array:
files = message.attachments
await member_object.send("**[MOD]** " + "**" + message.author.display_name + "**: ")
for file in files:
await member_object.send(file.url)
You are defining member_object as the first element in the message.mentions array, however your error of NoneType has no attribute suggests that there are no elements in that array and so member_object is actually equal to None not an instance of a class which has a send method.
You need to check your input to that function and ensure that when your code reaches that block it actually has the attributes that you are expecting

I am trying to send a msg to everyone that has set there channel, but I have problem sending msgs

In theory, the code should have sent a msg to all the servers that have set there channel! Altho it seems not to be working. I think its because I can't get the channel_id even tho I have done it in sqlite. Here is the code:
#client.event
async def on_ready():
print("The client is online!")
db = sqlite3.connect('entry.sqlite')
cursor = db.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS main(
guild_id TEXT,
channel_id,
user_id
)
''')
#client.command()
async def ping(ctx):
embed = discord.Embed(
title = "Pong!",
description = f"Your ping is {client.latency}ms !", color=0xf9c900)
await ctx.send(embed=embed)
#client.command()
async def public(ctx, channel:discord.TextChannel, winners: int, time: int, link:str, *, prize:str):
db = sqlite3.connect('entry.sqlite')
cursor = db.cursor()
channel_id = cursor.execute(f"SELECT channel_id FROM main WHERE guild_id = {ctx.guild.id}")
result = cursor.fetchone()
if result is None:
return
else:
for guild in client.guilds:
for channel in channel_id:
try:
embed = discord.Embed(
title = f"**Giving Away {prize}**",
description = f"React with 🎉 to enter! \n **{winners}** winner \n \n 🎊 Must be in **{link}** to enter!", color=0xf9c900)
msg = await ctx.send(embed=embed)
asyncio.sleep(1)
await msg.add_reaction('🎉')
asyncio.sleep(time)
except Exception:
continue
else:
break
#client.command()
async def setchannel(ctx, channel:discord.TextChannel):
if ctx.message.author.guild_permissions.manage_messages:
db = sqlite3.connect('entry.sqlite')
cursor = db.cursor()
cursor.execute(f"SELECT channel_id FROM main WHERE guild_id = {ctx.guild.id}")
result = cursor.fetchone()
if result is None:
sql = ("INSERT INTO main(guild_id, channel_id) VALUES(?,?)")
val = (ctx.guild.id, channel.id)
embed = discord.Embed(description=f":white_check_mark: succesfully added the giveaway channel {channel.mention}!",color=0x00ced1)
await ctx.send(embed=embed)
elif result is not None:
sql = ("UPDATE main SET channel_id = ? WHERE guild_id = ?")
val = (channel.id, ctx.guild.id)
embed = discord.Embed(description=f":white_check_mark: succesfully updated the giveaway channel {channel.mention}!",color=0x00ced1)
await ctx.send(embed=embed)
cursor.execute(sql, val)
db.commit()
cursor.close()
db.close()
The part I am trying to figure out is this part:
#client.command()
async def public(ctx, channel:discord.TextChannel, winners: int, time: int, link:str, *, prize:str):
db = sqlite3.connect('entry.sqlite')
cursor = db.cursor()
channel_id = cursor.execute(f"SELECT channel_id FROM main WHERE guild_id = {ctx.guild.id}")
result = cursor.fetchone()
if result is None:
return
else:
for guild in client.guilds:
for channel in channel_id:
try:
embed = discord.Embed(
title = f"**Giving Away {prize}**",
description = f"React with 🎉 to enter! \n **{winners}** winner \n \n 🎊 Must be in **{link}** to enter!", color=0xf9c900)
msg = await ctx.send(embed=embed)
asyncio.sleep(1)
await msg.add_reaction('🎉')
asyncio.sleep(time)
except Exception:
continue
else:
break
This part is suppose to send a message to the ones that have set there channel! But it isn't working and its not sending me any errors!
First of all, your SQL "SELECT channel_id FROM main WHERE guild_id = {ctx.guild.id}" is going to retrieve the channel_id for the guild that you ran the public command in.
Then, you get one row of data using cursor.fetchone(), but in your loop you are attempting to loop over channel_id, which is not the data you want, so I doubt your for loop is even running.

I can ban users if I do -ban [user] [reason], but if I do only -ban [user] it won't ban the user. How can I fix this?

Here's the code
#client.command(pass_context = True)
async def ban(ctx, user: discord.User,*, bugs: str):
if ctx.message.author.server_permissions.administrator or ctx.message.author.id == '562000458181246982':
embed = discord.Embed(title="", description="{} has been banned.".format(user.name), color=0x0072ff)
embed.add_field(name="Reason", value=bugs)
embed.set_author(name="Alpha Moderation", icon_url="https://media.discordapp.net/attachments/562005351353024525/569168417857208320/RealAlpha.png?width=355&height=356")
utc_dt = datetime.now(timezone.utc)
p = utc_dt.strftime(' Time - %H:%M:%S | Date - %d/%m/%Y')
utc = str( p)
txt=str(utc)
embed.set_footer(text=txt)
await client.say(embed=embed)
xd = ctx.message.server.name
embed = discord.Embed(title="", description="You have been banned from: " +xd, color=0x495c66)
embed.add_field(name="Action", value="Ban")
embed.add_field(name="Reason", value=bugs)
embed.set_author(name="Alpha Moderation", icon_url="https://media.discordapp.net/attachments/562005351353024525/569168417857208320/RealAlpha.png?width=355&height=356")
utc_dt = datetime.now(timezone.utc)
p = utc_dt.strftime(' %H:%M:%S • %d/%m/%Y ')
utc = str( p)
a=ctx.message.author
txt= str(a) + " | " + str(utc)
embed.set_footer(text="Banned by: " +txt)
await client.send_message(user, embed=embed)
await client.ban(user)
else:
embed=discord.Embed(title="Permission Denied.", description="<:alphaError:569178991349465088> You don't have permission to use this command.", color=0xEA1025)
await client.say(embed=embed)
https://media.discordapp.net/attachments/562005351353024525/569598677925232651/unknown.png?width=581&height=345
Since Python requires that all arguments be bound to a value, so when you won't pass value to bugs argument, function is missing required argument.
To fix this, you could set default value for bugs argument like this:
#client.command(pass_context=True)
async def ban(ctx, user: discord.User, *, bugs: str = None):
if bugs is None:
# do something when reason is not provided
# e.g. set some default reason value
bugs = "Preemptive ban"
# rest of your code

Resources