Ricardo B.
Ricardo B.

Reputation: 27

Discord.py: Send long messages

@bot.command(name='mlist', help='List of members.')
async def mlist(ctx):
    nl = "\n"
    await ctx.send(f'The member list is:\n{nl.join(memberList())}')

I have this code above that sends a list of current members to the channel. It worked fine until I started having a list that exceeds the discord message limit.
From what I found I have 2 options to handle this:

  1. split the list in parts to avoid the limit, which will make lots messages and make it harder to clean up channel.
  2. send the list as a text file, which I can't find a way of doing without creating, saving, opening and then deleting a new file every time.

Any advice on the best way of accomplishing my goal?

Upvotes: 1

Views: 5262

Answers (2)

Diggy.
Diggy.

Reputation: 6944

A way you could accomplish this is by having a message which has some reactions that allow you to flip through some "pages" of members?

The idea would use Client.wait_for():

Example:

import asyncio
import math

@bot.command()
async def members(ctx):
    members = [str(m) for m in ctx.guild.members]
    per_page = 10 # 10 members per page
    pages = math.ceil(len(members) / per_page)
    cur_page = 1
    chunk = members[:per_page]
    linebreak = "\n"
    message = await ctx.send(f"Page {cur_page}/{pages}:\n{linebreak.join(chunk)}")
    await message.add_reaction("◀️")
    await message.add_reaction("▶️")
    active = True

    def check(reaction, user):
        return user == ctx.author and str(reaction.emoji) in ["◀️", "▶️"]
                     # or you can use unicodes, respectively: "\u25c0" or "\u25b6"

    while active:
        try:
            reaction, user = await bot.wait_for("reaction_add", timeout=60, check=check)
        
            if str(reaction.emoji) == "▶️" and cur_page != pages:
                cur_page += 1
                if cur_page != pages:
                    chunk = members[(cur_page-1)*per_page:cur_page*per_page]
                else:
                    chunk = members[(cur_page-1)*per_page:]
                await message.edit(content=f"Page {cur_page}/{pages}:\n{linebreak.join(chunk)}")
                await message.remove_reaction(reaction, user)

            elif str(reaction.emoji) == "◀️" and cur_page > 1:
                cur_page -= 1
                chunk = members[(cur_page-1)*per_page:cur_page*per_page]
                await message.edit(content=f"Page {cur_page}/{pages}:\n{linebreak.join(chunk)}")
                await message.remove_reaction(reaction, user)
        except asyncio.TimeoutError:
            await message.delete()
            active = False

Upvotes: 1

Patrick Haugh
Patrick Haugh

Reputation: 61042

To accomplish your option 2, you need to create a file-like object, for which you can use io.BytesIO

import discord
from io import BytesIO
from discord.ext import commands

bot = commands.Bot("!")

@bot.command()
async def ex(ctx):
    member_names = (mem.display_name for mem in ctx.guild.members)
    as_bytes = map(str.encode, member_names)
    content = b"\n".join(as_bytes)
    await ctx.send("Member List", file=discord.File(BytesIO(content), "members.txt"))

bot.run('token')

Upvotes: 2

Related Questions