Word limit in an embed description - discord.py

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)

Related

discord.py file append rewrite the file instead of appending

When I want to append something to a file (with the append mode), it just erases everything before writing what I would like to append.
I have an on_voice_state_update event, when triggered, it checks if the user joined a specific channel. If yes: it creates a voice channel with some permissions for the user who created the voice channel. It is also supposed to append to a file called member_channel.txt this: {member.id}:{the_member's_voice_channel.id} but instead of adding this at the end of the file, it first erases everything and then add what I want to add.
Here are the codes:
#bot.event
async def on_voice_state_update(member, before, after):
if after.channel is not None and after.channel.id == 1059553884286230608:
guild = bot.get_guild(966749409314504774)
everyone_role = discord.utils.get(guild.roles, id = 966749409314504774)
community_role = discord.utils.get(guild.roles, id = 1006304076331483256)
muted_role = discord.utils.get(guild.roles, id = 1059109986258653244)
global member_channel
member_channel = await guild.create_voice_channel(name = f"Vocal de {member.name}")
await member_channel.edit(category = discord.utils.get(get_guild().channels, id = 1057730051321372692))
await member_channel.set_permissions(member, connect = True, manage_channels = True, manage_permissions = True, priority_speaker = True, move_members = True)
await member_channel.set_permissions(everyone_role, view_channel = False)
await member_channel.set_permissions(community_role, view_channel = True)
await member_channel.set_permissions(muted_role, speak = False)
await member.move_to(member_channel)
with open("member_channel.txt", "a") as file: # THIS IS WHAT
file.write(str(member.id) + ":" + str(member_channel.id) + "\n") # IS'NT WORKING
print(f"[{await get_hour()}] {member.name} created a temporary voice channel.")
#then we want to delete the channel if it is empty and equal to a member's channel, and also delete the line in member_channel.txt corresponding to this member and channel
elif before.channel is not None and len(before.channel.members) == 0:
new_file_value = ""
try:
with open("member_channel.txt", "r") as file:
lines = file.readlines()
splited_lines = []
for line in lines:
splited_lines.append((line.split(":")))
for lines in splited_lines:
for line in lines:
line.replace("\n", "")
if str(before.channel.id) in line:
await before.channel.delete()
del splited_lines[line.index(str(before.channel.id))]
for line in splited_lines:
print(new_file_value)
new_file_value += line
for ele in line:
print(new_file_value)
new_file_value += line + ":"
with open("member_channel.txt", "w+") as file:
file.write(new_file_value)
print(f"[{await get_hour()}] I deleted the temporary voice channel {member_channel.name}.")
file.close()
file.close()
except NameError:
return

discord.py problems with the checking

im trying to do a trivial discord bot, but with a "helper" it reveals you letter by letter the answer, each "x" senconds, but the problem is i can't to send the answer till the help is fully displayed
in the image the problem is cleary visible
this is the whole code
await ctx.send(a) #question
respuestas = b #answer
#reveal
string = respuestas[0]
blanked_string = [x if x.isspace() else "-" for x in string]
nonspace_indexes = [i for i, _ in enumerate(string)]
random.shuffle(nonspace_indexes)
for i in nonspace_indexes:
blanked_string[i] = string[i]
await ctx.send(''.join(blanked_string))
await asyncio.sleep(2)
#checking
def check(msg=discord.Message) -> True:
return msg.content.lower() in respuestas and msg.channel == ctx.message.channel
try:
guess = await bot.wait_for('message', timeout=6, check=check)
return await ctx.send(f"{guess.author.mention} first")
except asyncio.TimeoutError:
await ctx.send("time over")
#problem
https://i.stack.imgur.com/jlatG.png
note: im not trying to do a hangman
async def letters(response: str, channel: discord.TextChannel):
blanked_string = [x if x.isspace() else "-" for x in response]
nonspace_indexes = [i for i, _ in enumerate(response)]
random.shuffle(nonspace_indexes)
for i in nonspace_indexes:
blanked_string[i] = response[i]
await channel.send(''.join(blanked_string))
await asyncio.sleep(1)
#client.command()
async def game(ctx: commands.Context):
await ctx.send("Author of Python programming language...")
response = "Guido van Rossum"
letters_func = asyncio.create_task(letters(response, ctx.channel))
try:
player_response = await client.wait_for('message', check=lambda m: m.author == ctx.author and m.channel == ctx.channel, timeout=30)
except asyncio.TimeoutError:
letters_func.cancel()
await ctx.send("Time's up!")
else:
letters_func.cancel()
if player_response.content == response:
await ctx.send("Correct!")
else:
await ctx.send("Incorrect!")
Here is a possible resolution path for your problem. I took advantage of asyncio's presence to do this. You can test it, it works very well.
Be careful to adapt your response time to the length of your answer

set a time limit to rank discord.py

After several searches I have not found anything that would work out for me. I would like to have users recieve xp every 30 seconds but I don't know how. If said user writes a message they would get xp, but if they write again within the next 30 seconds of the other message they would not receive any xp. This would happen until the 30 seconds are up.
#client.event
async def on_message(message):
if message.author.bot:
print("Io sono il bot e non posso livellare :(")
return
if message.guild.id not in client.msg_dict:
#print(message.guild.id)
client.msg_dict[message.guild.id] = {}
#print(client.msg_dict[message.guild.id])
#print(message.author.id, client.msg_dict[message.guild.id])
if message.author.id in client.msg_dict[message.guild.id]:
#print("Test2")
if not (time.time() - client.msg_dict[message.guild.id][message.author.id]) > 30:
#print("Utente bloccato")
return # current time - last msg sent time is not > 30
xp = generateXP()
print(f"{message.author.name} ha ricevuto {str(xp)} xp")
cursor = levelsystem_db.cursor()
cursor.execute(f"SELECT user_xp FROM users WHERE client_id = {str(message.author.id)}")
result = cursor.fetchall()
print(result)
print(len(result))
if (len(result) == 0):
print("L'utente non รจ stato aggiunto al database.")
cursor.execute(f"INSERT INTO users VALUES({str(message.author.id)} ,{str(xp)} , 0)")
levelsystem_db.commit()
print("Aggiunta completata")
await level_up(cursor, xp, message.author, message)
else:
newXP = result[0][0] + xp
print(f"Gli xp di {message.author.name} sono aggiornati a {newXP}")
cursor.execute(f"UPDATE users SET user_xp = {str(newXP)} WHERE client_id = {str(message.author.id)}")
levelsystem_db.commit()
print(f"Aggiornamento degli xs di {message.author.name} completato.")
await level_up(cursor, newXP, message.author, message)
def generateXP():
return random.randint(5,10)
async def level_up(cursor, NewXP, user, message):
cursor.execute(f"SELECT user_level FROM users WHERE client_id = {str(message.author.id)}")
level = cursor.fetchall()
lvl_start = level[0][0]
lvl_end = int(NewXP ** (1/4))
print(str(lvl_start))
print(str(lvl_end))
if (str(lvl_start) < str(lvl_end)):
await message.channel.send(f"{user.mention} รจ salito al livello {lvl_end}")
print(f"Il livello di {message.author.name} si sta aggiornando al livello {lvl_end}")
cursor.execute(f"UPDATE users SET user_level = {str(lvl_end)} WHERE client_id = {str(message.author.id)}")
levelsystem_db.commit()
print(f"Aggiornamento del livello di {message.author.name} completato.")
else:
print("Non รจ abbastanza!")
pass
EDIT:I absolutely need some answers you can't find anything or the ones you find are obsolete!
Make a dict that holds user ids that messaged and remove the ids after 30 secs, and check using that in on_message
import time
#client.event
async def on_ready():
print("Ready")
client.msg_dict = {}
#client.event
async def on_message(message):
if message.author.bot:
print("Io sono il bot e non posso livellare :(")
return
if message.guild.id not in client.msg_dict:
client.msg_dict[message.guild.id] = {}
if message.author.id in client.msg_dict[message.guild.id]:
if not (time.time() - client.msg_dict[message.guild.id][message.author.id]) > 30:
return # current time - last msg sent time is not > 30
client.msg_dict[message.guild.id][message.author.id] = time.time() # change last msg sent time with current time as the user sent a msg now
xp = generateXP()
print(f"{message.author.name} ha ricevuto {str(xp)} xp")
cursor = levelsystem_db.cursor()
cursor.execute(f"SELECT user_xp FROM users WHERE client_id = {str(message.author.id)}")
result = cursor.fetchall()
print(result)
print(len(result))
if (len(result) == 0):
print("L'utente non รจ stato aggiunto al database.")
cursor.execute(f"INSERT INTO users VALUES({str(message.author.id)} ,{str(xp)} , 0)")
levelsystem_db.commit()
print("Aggiunta completata")
await level_up(cursor, xp, message.author, message)
else:
newXP = result[0][0] + xp
print(f"Gli xp di {message.author.name} sono aggiornati a {newXP}")
cursor.execute(f"UPDATE users SET user_xp = {str(newXP)} WHERE client_id = {str(message.author.id)}")
levelsystem_db.commit()
print(f"Aggiornamento degli xs di {message.author.name} completato.")
await level_up(cursor, newXP, message.author, message)
I finally found the solution using MySQL and the asyncio library.
This is the script I applied according to my needs
#client.event
async def on_message(message):
if message.author.bot:
return
xp = 5
cursor = levelsystem_db.cursor()
cursor.execute(f"SELECT message_id FROM anti_spam WHERE client_id = {str(message.author.id)}")
check_message = cursor.fetchall()
if (len(check_message) == 0):
cursor.execute(f"INSERT INTO anti_spam VALUES({str(message.id)}, {str(message.author.id)}, 1)")
levelsystem_db.commit()
else:
print("Non puoi livellare!")
return
#In between create your ranking system, giving user experience etc.
await asyncio.sleep(60)
cursor.execute(f"DELETE FROM anti_spam WHERE message_id = {str(message.id)}")
levelsystem_db.commit()
await client.process_commands(message)

Discord.py how to add a countdown to an embed

I have been trying to find a way to add a countdown in an embed but can't find anything. So when current_time reaches a certain time, it sends an embed and starts counting down in one of the fields.
await client.wait_until_ready()
channel = client.get_channel(auth)
while not client.is_closed():
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
print(current_time)
if current_time == "03:09:00":
embed = discord.Embed(
colour = discord.Colour.green(),
title = "test"
)
embed.set_image(url = "(img)") #
embed.set_thumbnail(url = "(img)") #
**embed.add_field(name="Timer", value ="??:??:??", inline = True) #Timer goes at ??:??:??
embed.add_field(name="Location", value ="adding later", inline = True)
await channel.send(embed=embed)
client.loop.create_task(background_task())```
Since its all in a async function, you could do something like this
#client.command()
async def countdown(ctx, *args):
embed = discord.Embed(
title='foo',
description='bar'
)
now = datetime.datetime.now()+datetime.timedelta(minutes=5)
embed.insert_field_at(
index=0,
name='countdown',
value=str(datetime.timedelta(minutes=5))
)
msg = await ctx.send(embed=embed)
while datetime.datetime.now() < now:
embed.remove_field(index=0)
embed.insert_field_at(
index=0,
name='countdown',
value=str(now-datetime.datetime.now())
)
await msg.edit(embed=embed)
asyncio.sleep(5)

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.

Resources