I'm trying to do a multiple choice button / reaction in discord using python (discord.py) -- something similar to the image below:
For example when it reacts to 2️⃣, that shows page 2, when it reacts to 3️⃣, that shows page 3 ...
Could anyone help me, please?
import discord
from discord.ext import commands
class Wiki(commands.Cog):
def __init__(self,bot):
self.bot=bot
#commands
#commands.command(name="wiki",aliases=["w"])
async def wiki(self,ctx):
page1=discord.Embed(
title='Page 1/3',
description='Description1',
colour=discord.Colour.orange()
)
page2=discord.Embed(
title='Page 2/3',
description='Description2',
colour=discord.Colour.orange()
)
page3=discord.Embed(
title='Page 3/3',
description='Description3',
colour=discord.Colour.orange()
)
pages=[page1,page2,page3]
message= await ctx.send(embed=page1)
await message.add_reaction('1️⃣')
await message.add_reaction('2️⃣')
await message.add_reaction('3️⃣')
emoji=""
if emoji=="1️⃣":
await message.edit_message(message,embed=pages[0])
if emoji=="2️⃣":
await message.edit_message(message,embed=pages[1])
if emoji=="3️⃣":
await message.edit_message(message,embed=pages[2])
def setup(bot):
bot.add_cog(Wiki(bot))
Take a look at the documentation for wait_for, which is how you should treat this kind of case. I won't spoonfeed you the code though, you should give it a fair shot yourself first.
Also, discord.py already has something built-in for embeds that change pages automatically based on reactions called menus, so it'll probably be easier to just use that instead of re-implementing it yourself.
Answering my own question.
I know it's not the best answer, but it works XD.
Any suggestion will be well accepted. Thank you all so much for your help.
import asyncio
import discord
from discord.ext import commands
class Wiki(commands.Cog):
def __init__(self,bot):
self.bot=bot
#commands
#commands.command(name="wiki",aliases=["w"])
async def wiki(self,ctx):
first_run = True
while True:
if first_run:
page1=discord.Embed(title='Page 1/3',description='Description1',colour=discord.Colour.orange())
first_run=False
msg = await ctx.send(embed=page1)
reactmoji = ["1️⃣","2️⃣","3️⃣"]
for react in reactmoji:
await msg.add_reaction(react)
def check_react(reaction, user):
if reaction.message.id != msg.id:
return False
if user != ctx.message.author:
return False
if str(reaction.emoji) not in reactmoji:
return False
return True
try:
res, user = await self.bot.wait_for('reaction_add', check=check_react)
except asyncio.TimeoutError:
return await msg.clear_reactions()
if user != ctx.message.author:
pass
elif '1️⃣' in str(res.emoji):
print('<<1️⃣>>')
await msg.remove_reaction("1️⃣",user)
await msg.edit(embed=page1)
elif '2️⃣' in str(res.emoji):
print('<<2️⃣>>')
page2=discord.Embed(title='Page 2/3',description='Description2',colour=discord.Colour.orange())
await msg.remove_reaction("2️⃣",user)
await msg.edit(embed=page2)
elif '3️⃣' in str(res.emoji):
print('<<3️⃣>>')
page3=discord.Embed(title='Page 3/3',description='Description3',colour=discord.Colour.orange())
await msg.remove_reaction("3️⃣",user)
await msg.edit(embed=page3)
def setup(bot):
bot.add_cog(Wiki(bot))
Related
my name is Mali my friend Env is trying to make something where it can give people roles if they have his server invite in their bio this is what he has so far:
async def status_check(guild):
while True:
async for member in guild.fetch_members():
for s in member.activities:
if isinstance(s, discord.CustomActivity):
if s == "discord.gg/drame":
await member.add_roles([discord.Object(960335274745937920)])
await asyncio.sleep(10)
status_check = True
I couldn’t think of anything because I am fairly new to coding
You can do something like this:
from discord.utils import get
#bot.event # or #client.event
async def on_member_update(before, after):
if after.guild.id == 926498246619189258: # Only attempt to add roles for your server
if after.activity and after.activity.name.lower() == "discord.gg/drame":
role_id = 960335274745937920
role = get(after.guild.roles, id=role_id)
await after.add_roles(role)
elif before.activity and before.activity.name.lower() == "discord.gg/drame" and not after.activity:
role_id = 960335274745937920
role = get(after.guild.roles, id=role_id)
await after.remove_roles(role)
The above will only execute if a member updates their bio/activity.
If you want to check the existing bio/activity of members, this may help.
What I'm trying to do: This is a similar situation to a question I previously asked, I am making a multiplayer game. I wanted to get multiple user inputs at the same time, basically the situation in another question I had found (multiple wait_for_messages wanted discord.py).
My Problem: I need to send messages to a different set of people each time. Basically, one game may have 3 players, while another might have 5 players. The original aim was also to send a message simultaneously to a user's dms and have them answer the input from there. I am unsure how to define the amount of wait_fors I need in my code.
Code attempt 1:
# inside a cog
#commands.command()
async def bagpie(self, ctx, *members: discord.Member):
members = list(members)
if ctx.author not in members:
members.append(ctx.author)
if len(members) > 3:
return
# making checks
def check1(msg):
return msg.author == members[0]
def check2(msg):
return msg.author == members[1]
def check3(msg):
return msg.author == members[2]
# waiting for multiple messages with the checks
ret = await asyncio.gather(
await self.bot.wait_for("message", timeout=10, check=check1),
await self.bot.wait_for("message", timeout=10, check=check2),
await self.bot.wait_for("message", timeout=10, check=check3),
return_exceptions = True
)
# Test for errors
ret = [r if not isinstance(r, Exception) else None for r in ret]
msg1, msg2, msg3 = ret # *ret would cause an error to occur
# setup embed to send final product
fin_string = ""
count = 0
msg_list = [msg1, msg2, msg3]
for member in members:
fin_string += f"{member} says: {msg_list[count]}"
count += 1
embed = discord.Embed(title="This is what you said!", description=fin_string)
await ctx.send(embed=embed)
Result: As you can see, despite there being inputs given, the bot does not respond and instead reverts to the timeout.
Code Attempt 2:
# couldn't get this to work in a cog, so this one is not in a cog
# checks if it's a dm and if author is given member
def is_dm_check(member):
def inner_check(msg):
return msg.author.id==member.id and msg.guild is None
return inner_check
# sends message to member and waits for the message
async def get_input(member):
await member.send("Please provide an input:")
return client.wait_for('message', check=is_dm_check(member), timeout=75)
#client.command()
async def play_game(ctx, members: commands.Greedy[discord.Member]=None):
if not members:
await ctx.send("No Players")
return
if ctx.author not in members:
members.append(ctx.author)
responses = asyncio.gather(*map(get_input, members))
for member, response in zip(members, responses):
await ctx.send(f"{member.mention}: {response.content}")
Result: Messages were supposedly sent simultaneously, however it still throws an error.
How can I edit embed with emoji buttons in discord.py?
I was making it like this.. but it doesn't works..
#client.event
async def on_message(message):
if message.content.startswith("!menu"):
embed=discord.Embed(color=0x00FFFF, title=f'Menu', description= f'🔴 - test1 \n🟠 - test2 \n🟡 - test3 \n🟢 - test4 \n🔵 - test5 \n🟣 - test6', timestamp=message.created_at)
embed.set_footer(text=f'-', icon_url=message.author.avatar_url)
msg = await message.channel.send(embed=embed)
await msg.add_reaction('🔴')await msg.reaction_add('🟠')
await msg.add_reaction('🟡')
await msg.add_reaction('🟢')
await msg.add_reaction('🔵')
await msg.add_reaction('🟣')
if str(msg.add_reaction) == '🔴':
embed1=discord.Embed(color=0x00FFFF, title=f'edit1', description= f'test1')
await msg.edit(embed=embed1)
I want some edit codes!!
Welcome to StackOverflow, you can use discord.ext.menus. Here's how you need to install it.
pip install git+https://github.com/Rapptz/discord-ext-menus.
Then you can do something like this.
import discord
from discord.ext import menus
class ColorMenu(menus.Menu):
def __init__(self, embed):
super().__init__(timeout=30.0, delete_message_after=True)
self.embed = embed
self.result = None
async def send_initial_message(self, ctx, channel):
return await channel.send(embed=self.embed)
#menus.button('🔴')
async def red_button(self, payload):
# do what ever you want with this.
# right now I'm going to just edit the message
self.embed.description = 'test1'
self.embed.title = 'title1'
self.message.edit(embed=self.embed)
# do the same thing for other reactions
Then make a new command and instantiate the class, like this:
#bot.command()
async def menu(ctx):
color_menu = ColorMenu()
color_menu.start(ctx)
And you're done.
Good luck with your bot.
I have the following code to handle multiple intents,
Code
async def on_message_activity(self, turn_context: TurnContext):
recognizer_result = await self.luis.recognize(self.recognizer, turn_context)
intent = self.luis.get_top_intent(recognizer_result)
await self.process_intent(turn_context, recognizer_result, intent)
async def process_intent(self, turn_context: TurnContext, recognizer_result, intent):
if intent == 'Greeting_Wishes':
await greeting_wishes(turn_context, user_info)
elif intent == 'Greeting_Question':
await greeting_question(turn_context)
elif intent == 'Movement':
dialog = Movement(recognizer_result)
await DialogHelper.run_dialog(
dialog,
turn_context,
self.dialog_state
)
Problem
Greeting intent is working fine
Movement intent is properly taking to the configured dialog but after asking a couple of inputs to the user and when the user enters their value it is either going back to greeting intent or going nowhere since the intent is None
Can someone help how to handle multiple intents with dialogs?
Any help would be appreciated!
I ended up having one main dialog and extended the other dialogs depending upon the other intent. Look at the code sample below,
async def on_message_activity(self, turn_context: TurnContext):
recognizer_result = await self.luis.recognize(self.recognizer, turn_context)
intent = self.luis.get_top_intent(recognizer_result)
await self.process_intent(turn_context, recognizer_result, intent)
async def process_intent(self, turn_context: TurnContext, recognizer_result, intent):
if intent == "Greeting_Wishes" and not entity:
await greeting_wishes(turn_context, user_info)
return
if intent == "Greeting_Question" and not entity:
await greeting_question(turn_context)
return
dialog = MainDialog(self.luis, intent, recognizer_result)
await DialogHelper.run_dialog(
dialog,
turn_context,
self.conversation_state.create_property("DialogState")
)
main_dialog.py
Within the main dialog, I'll check for the intent and begin the appropriate dialog.
class MainDialog(ComponentDialog):
def __init__(self, luis, intent, recognizer_result):
super(MainDialog, self).__init__(MainDialog.__name__)
self.luis = luis
self.intent = intent
self.recognizer_result = recognizer_result
self.add_dialog(SampleDialog1())
self.add_dialog(SampleDialog2())
self.add_dialog(
WaterfallDialog(
"main_dialog_id", [self.main_step]
)
)
self.initial_dialog_id = "main_dialog_id"
async def main_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
dialog_detail = self.luis.get_entities(self.intent, self.recognizer_result)
if self.intent == "one":
return await step_context.begin_dialog(SampleDialog1.__name__, dialog_detail)
elif self.intent == "two":
return await step_context.begin_dialog(SampleDialog2.__name__, dialog_detail)
How can i make this code icaseSensitive? I have tried bot = commands.Bot(command_prefix=';', case_insensitive=True
Is the code i have here on the rewrite branch? I know how on async def on_message but have heard it is not that smart to use async def on_message
Code:
import discord
from discord.ext import commands
from discord.ext.commands import Bot
import asyncio
bot = commands.Bot(command_prefix=';', case_insensitive=True)
#bot.command(pass_context=True)
#commands.has_role("Admin")
async def info(ctx, user: discord.Member):
embed = discord.Embed(title="{}'s info:".format(user.name), description="Here is his description. Bounty is around 1000 Dubloons", color=0x00ff00)
embed.add_field(name="Navn", value=user.name, inline=True)
embed.add_field(name="ID", value=user.id, inline=True)
embed.add_field(name="Status", value=user.status, inline=True)
embed.add_field(name="Høyeste rolle", value=user.top_role)
embed.add_field(name="Ble med", value=user.joined_at)
embed.set_thumbnail(url=user.avatar_url)
await bot.say(embed=embed)
edit:
from itertools import product
def aliases(info):
return [''.join(item) for item in product(*((c.lower(), c.upper()) for c in info))]
#bot.command(pass_context=True, aliases=aliases('info'))
#commands.has_role("Admin")
async def info(ctx, user: discord.Member):
embed = discord.Embed(title="{}'s info:".format(user.name), description="Here is his description. Bounty is around 1000 Dubloons", color=0x00ff00)
embed.add_field(name="Navn", value=user.name, inline=True)
embed.add_field(name="ID", value=user.id, inline=True)
embed.add_field(name="Status", value=user.status, inline=True)
embed.add_field(name="Høyeste rolle", value=user.top_role)
embed.add_field(name="Ble med", value=user.joined_at)
embed.set_footer(text="© Solmester123456 // Thomas")
embed.set_thumbnail(url=user.avatar_url)
await bot.say(embed=embed)
Try running import discord; print(discord.__version__). The rewrite branch is 1.0, the async branch is 0.16. I suspect you're on the async branch.
A stopgap solution would be to register every mixed capitlization as an alias, something like
from itertools import product
def aliases(word):
variations = (''.join(item) for item in product(*((c.lower(), c.upper()) for c in word)))
return [item for item in variations if item != word]
# registering the name of the coroutine as an alias causes it to fail
#bot.command(pass_context=True, aliases=aliases('info'))
#commands.has_role("Admin")
async def info(ctx, user: discord.Member):
...
Edit: This was previously not working because product returns tuples instead of strings, so we need to join them to make words.