Discord.py 如何拆分机器人消息?

Discord.py How do I split a bots message?

所以,我正在处理一个不和谐的信息机器人,这是命令之一。

@client.command()
async def rd(ctx):
    embed = discord.Embed(title="**[R&D Cost at every level]:**")
    embed.add_field(name="**Level//All Units ATK Bonus//March Size Increase//R&D Cost**", value= "|", inline=False)
    embed.add_field(name="6    0.6%    0    10", value='.', inline=False)
    embed.add_field(name="7    0.7%    0    20", value='.', inline=False)
    embed.add_field(name="8    0.8%    0    30", value='.', inline=False)
    embed.add_field(name="9    0.9%    0    35", value='.', inline=False)
    embed.add_field(name="10    1.0%    0    40", value='.', inline=False)
    embed.add_field(name="11    1.2%    0    45", value='.', inline=False)
    embed.add_field(name="12    1.5%    0    50", value='.', inline=False)
    embed.add_field(name="13    2.0%    0    60", value='.', inline=False)
    embed.add_field(name="14    2.5%    0    TBD", value='.', inline=False)
    embed.add_field(name="15    3.0%    0    TBD", value='.', inline=False)
    embed.add_field(name="16    3.5%    0    TBD", value='.', inline=False)
    embed.add_field(name="17    4.0%    0    TBD", value='.', inline=False)
    embed.add_field(name="18    4.5%    0    TBD", value='.', inline=False)
    embed.add_field(name="19    5.0%    0    TBD", value='.', inline=False)
    embed.add_field(name="20    5.5%    0    TBD", value='.', inline=False)
    embed.add_field(name="21    6.0%    0    TBD", value='.', inline=False)
    embed.add_field(name="22    6.5%    0    TBD", value='.', inline=False)
    embed.add_field(name="23    7.0%    0    TBD", value='.', inline=False)
    embed.add_field(name="24    7.5%    0    TBD", value='.', inline=False)
    embed.add_field(name="25    8.0%    1    TBD", value='.', inline=False)
    embed.add_field(name="26    8.5%    1    TBD", value='.', inline=False)
    embed.add_field(name="27    9.0%    1    TBD", value='.', inline=False)
    embed.add_field(name="28    9.5%    1    TBD", value='.', inline=False)
    embed.add_field(name="29    10.0%    1    TBD", value='.', inline=False)
    embed.add_field(name="30    10.5%    2    TBD", value='.', inline=False)
    embed.add_field(name="31    11.0%    2    TBD", value='.', inline=False)
    embed.add_field(name="32    11.5%    2    TBD", value='.', inline=False)
    embed.add_field(name="33    12.0%    2    1.27K", value='.', inline=False)
    embed.add_field(name="34    12.5%    2    1.46K", value='.', inline=False)
    embed.add_field(name="35    13.0%    3    1.87K", value='.', inline=False)
    embed.add_field(name="36    13.5%    3    2.02K", value='.', inline=False)
    embed.add_field(name="37    14.0%    3    2.18K", value='.', inline=False)
    embed.add_field(name="38    14.5%    3    2.36K", value='.', inline=False)
    embed.add_field(name="39    15.0%    3    2.54K", value='.', inline=False)
    embed.add_field(name="40    15.5%    4    2.73K", value='.', inline=False)
    embed.add_field(name="41    16.0%    4    2.87K", value='.', inline=False)
    embed.add_field(name="42    16.5%    4    3.07K", value='.', inline=False)
    embed.add_field(name="43    17.0%    4    3.29K", value='.', inline=False)
    embed.add_field(name="44    17.5%    4    3.51K", value='.', inline=False)
    embed.add_field(name="45    18.0%    5    3.74K", value='.', inline=False)
    embed.add_field(name="46    18.5%    5    3.99K", value='.', inline=False)
    embed.add_field(name="47    19.0%    5    4.09K", value='.', inline=False)
    embed.add_field(name="48    19.5%    5    4.34K", value='.', inline=False)
    embed.add_field(name="49    20.0%    5    4.44K", value='.', inline=False)
    embed.add_field(name="50    20.5%    6    4.54K", value='.', inline=False)

该命令运行良好,除了 discord 在“embed.add_field(name="29 10.0% 1 TBD", value='.', inline=False)” 上切断了消息,因为单个消息中的最大字符数限制。

我该如何将这条消息分成几页?我看到哪里可以使用表情符号来滚动浏览信息,但我不确定如何将其应用到此处的此命令。

或者我怎样才能让它 post 变成多条消息而不是试图 post 变成一整条消息?

非常感谢任何帮助!

这是我在开始实现按钮之前用来处理分页的代码

async def paginate(
    ctx: discord.ext.commands.context.Context,
    *embed_pages: typing.Union[discord.Embed, list[discord.Embed]],
    content=None,
    overwrite_footer=True,
    timeout=None,
):

    if isinstance(embed_pages[0], list):
        embed_pages = embed_pages[0]

    every_embed = list()
    if overwrite_footer:
        for index, each_embed in enumerate(embed_pages):
            each_embed.remove_footer()
            each_embed.set_footer(text=f"Page {index + 1} of {len(embed_pages)}")
            every_embed.append(each_embed)
    else:
        every_embed = embed_pages[:]

    sent_embed = await ctx.send(
        content=content, embed=every_embed[0]
    )  # Send the first page
    page_index = 0  # Set the starting index

    reactions = ["⬅️", "", "➡️"]
    for each_reaction in reactions:
        await sent_embed.add_reaction(each_reaction)

    while True:
        try:
            payload = await bot.wait_for(
                "raw_reaction_add",
                check=lambda payload: payload.message_id == sent_embed.id
                and not payload.member == bot.user
                and payload.member.id
                == ctx.author.id,  # Do this if you want it to be author-only
                timeout=timeout,
            )
        except asyncio.TimeoutError:
            # timeout has been hit
            if overwrite_footer:
                every_embed[page_index].remove_footer()
                every_embed[page_index].set_footer(
                    text="Pagination traversal has timed out."
                )
                await sent_embed.edit(embed=every_embed[page_index])
                try:
                    await every_embed.clear_reactions()
                except:
                    pass
            return
        else:
            try:
                await sent_embed.remove_reaction(payload.emoji, payload.member)
            except discord.Forbidden:
                # Bot does not have permission
                pass

            if (
                str(payload.emoji.name) not in reactions
            ):  # Some user reacted with something else
                pass

            elif str(payload.emoji.name) == reactions[0]:  # Previous page
                if not page_index == 0:
                    page_index -= 1
                else:
                    page_index = len(every_embed) - 1
                await sent_embed.edit(embed=every_embed[page_index], content=content)

            elif str(payload.emoji.name) == reactions[1]:  # Goto page 0
                page_index = 0
                await sent_embed.edit(embed=every_embed[page_index], content=content)

            else:
                if not page_index == (len(every_embed) - 1):
                    page_index += 1
                else:
                    page_index = 0
                await sent_embed.edit(embed=every_embed[page_index], content=content)

此函数是协程,必须 awaited,第一个参数必须是 ctx(上下文),其余参数可以是 discord.Embed 对象或单个包含上述 discord.Embed.

实例的列表

其余参数是可选的且不言自明。

这是一个用例:

import discord
import os
import asyncio
import typing
import Lorem  # Custom module
from discord.ext import commands
from dotenv import load_dotenv

load_dotenv()
bot = commands.Bot(command_prefix=">")


async def paginate(
    ctx: discord.ext.commands.context.Context,
    *embed_pages: typing.Union[discord.Embed, list[discord.Embed]],
    content=None,
    overwrite_footer=True,
    timeout=None,
):

    if isinstance(embed_pages[0], list):
        embed_pages = embed_pages[0]

    every_embed = list()
    if overwrite_footer:
        for index, each_embed in enumerate(embed_pages):
            each_embed.remove_footer()
            each_embed.set_footer(text=f"Page {index + 1} of {len(embed_pages)}")
            every_embed.append(each_embed)
    else:
        every_embed = embed_pages[:]

    sent_embed = await ctx.send(
        content=content, embed=every_embed[0]
    )  # Send the first page
    page_index = 0  # Set the starting index

    reactions = ["⬅️", "", "➡️"]
    for each_reaction in reactions:
        await sent_embed.add_reaction(each_reaction)

    while True:
        try:
            payload = await bot.wait_for(
                "raw_reaction_add",
                check=lambda payload: payload.message_id == sent_embed.id
                and not payload.member == bot.user
                and payload.member.id
                == ctx.author.id,  # Do this if you want it to be author-only
                timeout=timeout,
            )
        except asyncio.TimeoutError:
            # timeout has been hit
            if overwrite_footer:
                every_embed[page_index].remove_footer()
                every_embed[page_index].set_footer(
                    text="Pagination traversal has timed out."
                )
                await sent_embed.edit(embed=every_embed[page_index])
                try:
                    await every_embed.clear_reactions()
                except:
                    pass
            return
        else:
            try:
                await sent_embed.remove_reaction(payload.emoji, payload.member)
            except discord.Forbidden:
                # Bot does not have permission
                pass

            if (
                str(payload.emoji.name) not in reactions
            ):  # Some user reacted with something else
                pass

            elif str(payload.emoji.name) == reactions[0]:  # Previous page
                if not page_index == 0:
                    page_index -= 1
                else:
                    page_index = len(every_embed) - 1
                await sent_embed.edit(embed=every_embed[page_index], content=content)

            elif str(payload.emoji.name) == reactions[1]:  # Goto page 0
                page_index = 0
                await sent_embed.edit(embed=every_embed[page_index], content=content)

            else:
                if not page_index == (len(every_embed) - 1):
                    page_index += 1
                else:
                    page_index = 0
                await sent_embed.edit(embed=every_embed[page_index], content=content)


@bot.event
async def on_ready():
    print(f"Sucessfully logged in as {bot.user}")


@bot.command()
async def start(ctx):

    await paginate(
        ctx,
        [
            discord.Embed(title="Answered by Achxy!", description=Lorem.lorem(6))
            for _ in range(100)
        ],
    )
    # We just generated 100 pages of Lorem Ipsum :D


@bot.command()
async def ping(ctx):
    # I made this command just to prove that the while loop earlier isn't blocking.
    embed = discord.Embed(
        title="Pong! ",
        description=f"Current Latency of the bot is {round(bot.latency * 1000)}ms",
    )
    await ctx.reply(embed=embed)


bot.run(os.getenv("DISCORD_TOKEN"))

此代码将带来以下分页输出:

https://imgur.com/a/tmwGhpc