Part 2 - Lightbulb Bot#

Lightbulb is a command handler for Hikari, making it easy to create commands.

So to start using Lightbulb, let’s change our bot.py a little (new code has been highlighted):

 1import asyncio
 2import os
 3
 4import dotenv
 5import hikari
 6import lightbulb
 7
 8dotenv.load_dotenv()
 9
10bot = lightbulb.BotApp(
11    os.environ["BOT_TOKEN"],
12    intents=hikari.Intents.ALL,
13    prefix="+",
14    banner=None,
15)
16
17
18@bot.command
19@lightbulb.command("ping", description="The bot's ping")
20@lightbulb.implements(lightbulb.PrefixCommand, lightbulb.SlashCommand)
21async def ping(ctx: lightbulb.Context) -> None:
22    await ctx.respond(f"Pong! Latency: {bot.heartbeat_latency*1000:.2f}ms")
23
24
25if __name__ == "__main__":
26    if os.name == "nt":
27        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
28
29    bot.run()
  • Line 6 - We’ve imported lightbulb now too

  • Line 10-15 - We’ve used lightbulb to create the bot, adding
    • a prefix kwarg set to "+", for text-based commands

    • a banner kwarg set to None, disabling the hikari banner that appears when the bot starts
      This isn’t necessary, but the banner can get a little annoying after a while (sorry dav >_>)
  • Line 18-22 - Creates a command with the lightbulb bot named ping which works the same as the old ping command, responding with Pong! and the bot’s heartbeat latency

Now let’s run the bot again!

You should see a slightly different output this time:

I 2022-08-13 16:40:23,476 hikari.bot: you can start 998 sessions before the next window which starts at 2022-08-13 17:23:11.910600+01:00; planning to start 1 session...
I 2022-08-13 16:40:24,051 hikari.gateway.0: shard is ready: 1 guilds, Hikari#1093 (1007678609466601492), session '9c0a984004cdf4ed7d52ee1343f44121' on v8 gateway
I 2022-08-13 16:40:24,368 lightbulb.internal: Processing guild application commands
I 2022-08-13 16:40:24,973 lightbulb.internal: Processing application commands for guild 765236394577756171
I 2022-08-13 16:40:25,250 lightbulb.internal: Processing global application commands
I 2022-08-13 16:40:25,517 lightbulb.internal: Application command processing completed
I 2022-08-13 16:40:25,520 hikari.bot: started successfully in approx 2.35 seconds

Again, if you run the command +ping in your server, the bot should respond with it’s heartbeat latency.

Now, try typing /ping in Discord. A command should appear, with your bot’s avatar next to it:

_static/ping_cmd.png

Hit enter, and let’s run this new command!

_static/ping_2.png

We’ve just made a slash command! By passing lightbulb.SlashCommand to the @lightbulb.implements decorator, lightbulb will turn the command into a slash command, as well as a text-based prefix command (lightbulb.PrefixCommand).

Note

If you wanted to make your commands slash-only, you can remove the prefix kwarg on line 14 and lightbulb.PrefixCommand from the implements decorator.

Command Options#

Commands, both prefix and slash, can have options. Discord supports quite a few options types for slash commands.

Let’s make a new command using some of these option types to demonstrate them!

After your ping command, add this:

 1@bot.command
 2@lightbulb.option("ping", "Role to ping with announcement.", type=hikari.Role)
 3@lightbulb.option(
 4    "channel", "Channel to post announcement to.", type=hikari.TextableChannel
 5)
 6@lightbulb.option("image", "Announcement attachment.", type=hikari.Attachment)
 7@lightbulb.option("message", "The message to announce.", type=str)
 8@lightbulb.command("announce", "Make an announcement!", pass_options=True)
 9@lightbulb.implements(lightbulb.PrefixCommand, lightbulb.SlashCommand)
10async def announce(
11    ctx: lightbulb.Context,
12    message: str,
13    image: hikari.Attachment,
14    channel: hikari.InteractionChannel,
15    ping: hikari.Role,
16) -> None:
17    embed = hikari.Embed(
18        title="Announcement!",
19        description=message,
20    )
21    embed.set_image(image)
22
23    await ctx.bot.rest.create_message(
24        content=ping.mention,
25        channel=channel.id,
26        embed=embed,
27        role_mentions=True,
28    )
29
30    await ctx.respond(
31        f"Announcement posted to <#{channel.id}>!", flags=hikari.MessageFlag.EPHEMERAL
32    )
  • Line 2-8 - Specifying the options for our command
    • You can see that we’ve specified a type for each option, such as hikari.Role, hikari.TextableChannel and hikari.Attachment

    • Using built-in Python types such as str and int is also valid (Line 7)

  • Line 12-15 - We’ve passed our options as parameters to the command’s function
    • NOTE: The parameters must be named exactly as the options

    • You cannot, for example, call your message parameter msg
      Lightbulb will error if you do so
  • Line 17-21 - Create an embed, setting its description to the message our author gave, and the image to the image they chose too
    We’ll go into more detail on creating embeds in the next part (Part 3 - Making a lightbulb extension)
  • Line 23-28 - Send the message to the give channel, pinging the role given in the command options
    • NOTE: To ping everyone with the role, you must have set role_mentions to True, and the bot must have the Mention All Roles permission in the guild

  • Line 30-32 - Respond to the interaction with an ephemeral message, stating where the announcement has been posted

_static/announcement_1.png _static/announcement_2.png _static/announcement_3.png _static/announcement_4.png

Read the docs - Commands