Reputation: 55
I would like my leaderboard to split into multiple pages depending on how many users there are. For example, if there are 5 users, only one page remains, instead if there are 23 users it divides them into 3 pages of which the first 2 show 10 users while the last shows the last 3 users left. I've tried many ways and I've gotten to this point where I don't really know what to do. Can you solve? Any method is accepted as long as it works.
@client.command()
async def leaderboard(ctx):
cursor = levelsystem_db.cursor()
cursor.execute("SELECT users.user_level, users.user_xp, users.client_id\nFROM users\nORDER BY users.user_level DESC , users.user_xp DESC")
leaderboard = cursor.fetchall()
embed = discord.Embed(
title=f"Leaderboard del {ctx.guild.name}",
colour=0x003399
)
for i, pos in enumerate(leaderboard, start=1):
lvl, xp, member_id = pos
cursor.execute(f"SELECT xp_level FROM levels WHERE level = {lvl+1}")
xp_level = cursor.fetchall()
xp_level = xp_level[0][0]
member = await client.fetch_user(member_id)
sorted_users = ## get all the members and sort them...
pages = grouper(sorted_users, 10)
print(pages)
embed.add_field(
name=f"{i}. {member.display_name}",
value=f"Livello attuale: {lvl}\n\t\tXP: {xp}/{xp_level}\n",
inline=False
)
await ctx.send(embed=embed)
def grouper(iterable, n, fillvalue=None):
args = [iter(iterable)] * n
return zip_longest(*args, fillvalue=fillvalue)
Upvotes: 2
Views: 812
Reputation: 1037
You can paginate the embeds with reactions:
import asyncio
@client.command()
async def leaderboard(ctx):
cursor = levelsystem_db.cursor()
cursor.execute("SELECT user_level, user_xp, client_id FROM users ORDER BY user_level DESC, user_xp DESC")
users = cursor.fetchall()
pages = []
page_count = -(-len(users)//10)) #will return 3 if users' length is 23
for i in range(page_count):
embed = discord.Embed(
title = f"Leaderboard del {ctx.guild.name}",
colour = 0x003399
)
embed.set_footer(
text = f"Page {i + 1}/{page_count}"
)
for rank, data in enumerate(users[i * 10:i * 10 + 10], start=i * 10 + 1):
level = data[0]
xp = data[1]
user = await client.fetch_user(data[2])
embed.add_field(
name = f"#{rank} {user}",
value = f"Level: {level}\nExperience: {xp}"
inline = False
)
pages.append(embed)
index = 0
message = await ctx.send(embed=pages[0])
emojis = ["◀️", "⏹", "▶️"]
for emoji in emojis:
await message.add_reaction(emoji)
while not client.is_closed():
try:
react, user = await client.wait_for(
"reaction_add",
timeout = 60.0,
check = lambda r, u: r.emoji in emojis and u.id == ctx.author.id and r.message.id == message.id
)
if react.emoji == emojis[0] and index > 0:
index -= 1
elif react.emoji == emojis[1]:
await message.delete()
break
elif react.emoji == emojis[2] and index < len(pages) - 1:
index += 1
await message.edit(embed=pages[index])
except asyncio.TimeoutError:
await message.delete()
break
Upvotes: 2
Reputation: 1415
Idk if that's what you mean but try this:
import math
@client.command()
async def test(ctx):
users = [
"user1",
"user2",
"user3",
"user4",
"user5",
"user6",
"user7",
"user8",
"user9",
"user10",
"user11",
"user12",
"user13",
"user14",
"user15",
"user16",
"user17",
"user18",
"user19",
"user20",
"user21",
"user22",
"user23",
]
pages = {}
numOfPages = math.ceil(len(users) / 10)
j = 0
for i in range(numOfPages):
pages[f"page{i}"] = discord.Embed(title=f"Page {i+1}")
displayUsers = ""
while j < 10 + i * 10:
try:
displayUsers += users[j] + "\n"
except:
break
j += 1
pages[f"page{i}"].add_field(name="Users:", value=displayUsers)
await ctx.send(embed=pages[f"page{i}"])
It creates discord.Embed
objects accordingly to user count with the for loop and then sends them after each other.
Upvotes: 0
Reputation: 327
Per Discord's documentation on embed limits, found here, you can have up to 25 field objects and the embed should not exceed over 6000 characters maximum.
With this information in mind, you could create a function that keeps track of the character count and field count. Once one of these limits is exceeded, a separate "page" should be created to still keep the embed under these limits.
You will need to store the current state of the message and have a reaction_add event listener. In your reaction_add event listener, you will need to check the message again and check what page is it at and edit the message to have the new embed.
I hope this helps. I'll check the comments and help you if you get stuck!
Upvotes: 0