Part 7 - Miru, an optional component handler#
Miru is an optional component handler for hikari, making it much simpler to add components to messages, and to handle component interactions too.
We’ll need to edit bot.py
a little bit to get miru working.
At the top of the file, import miru:
import miru
And just above bot.load_extensions_from("./extensions/")
add:
miru.load(bot)
Now we need to edit fun.py
.
At the top of the file, import miru:
import miru
And now beneath our animal
command, add the following:
1class AnimalView(miru.View):
2 def __init__(self, author: hikari.User) -> None:
3 self.author = author
4 super().__init__(timeout=60)
5
6 @miru.select(
7 custom_id="animal_select",
8 placeholder="Pick an animal",
9 options=[
10 miru.SelectOption("Dog", "dog", emoji="🐶"),
11 miru.SelectOption("Cat", "cat", emoji="🐱"),
12 miru.SelectOption("Panda", "panda", emoji="🐼"),
13 miru.SelectOption("Fox", "fox", emoji="🦊"),
14 miru.SelectOption("Red Panda", "red_panda", emoji="🐼"),
15 miru.SelectOption("Koala", "koala", emoji="🐨"),
16 miru.SelectOption("Bird", "bird", emoji="🐦"),
17 miru.SelectOption("Racoon", "racoon", emoji="🦝"),
18 miru.SelectOption("Kangaroo", "kangaroo", emoji="🦘"),
19 ],
20 )
21 async def select_menu(self, select: miru.Select, ctx: miru.Context) -> None:
22 animal = select.values[0]
23 async with ctx.app.d.aio_session.get(
24 f"https://some-random-api.ml/animal/{animal}"
25 ) as res:
26 if res.ok:
27 res = await res.json()
28 embed = hikari.Embed(description=res["fact"], colour=0x3B9DFF)
29 embed.set_image(res["image"])
30
31 animal = animal.replace("_", " ")
32
33 await ctx.edit_response(
34 f"Here's a {animal} for you! :3", embed=embed, components=[]
35 )
36 else:
37 await ctx.edit_response(
38 f"API returned a {res.status} status :c", components=[]
39 )
40
41 async def on_timeout(self) -> None:
42 await self.message.edit("The menu timed out :c", components=[])
43
44 async def view_check(self, ctx: miru.Context) -> bool:
45 return ctx.user.id == self.author.id
46
47
48@fun_group.child
49@lightbulb.command("animal2", "Get a fact + picture of a cute animal :3")
50@lightbulb.implements(lightbulb.PrefixCommand, lightbulb.SlashSubCommand)
51async def animal_subcommand_2(ctx: lightbulb.Context) -> None:
52 view = AnimalView(ctx.author)
53 resp = await ctx.respond(
54 "Pick an animal from the dropdown :3", components=view.build()
55 )
56 msg = await resp.message()
57
58 view.start(msg)
59 await view.wait()
This new animal2
command produces the exact same result as the first animal
command, but it’s much easier to read
and understand at a glance, and adding buttons or other select menus would be incredibly easy.
Line 1 - Subclass
miru.View
, to create our customAnimalView
classLine 4 - Initialise our view with a timeout of 60 seconds
Line 6-20 - Create our select menu, with the same custom ID, placeholder and options as before
Line 22-39 - Perform the same request as before, and respond to the interaction with an embed
- Line 41-45 - Set our timeout function, and a view check
Line 48-50 - Create a second animal command, called “
animal2
”Line 52 - Create an instance of
AnimalView
Line 53-55 - Respond to the command interaction with our message and components
Line 58 - Start the view
Line 59 - Wait for the view to finish
Note
If you want to learn how to use buttons and more with Miru, check out the Miru guides, written by Miru’s creator: https://hikari-miru.readthedocs.io/en/latest/getting-started.html