How to add Select Table to the response? - discord.py

How can I add a select option to the bot's response so when I select one, it edits the message with another content?
Please help me. I do not have a example code just to add this to.

Those select menus or dropdowns are available in discord.py 2.0
Example
import discord
from discord import commands, ui
class Dropdown(ui.Select):
def __init__(self):
# The options which can be chosen inside the dropdown
options = [
discord.SelectOption(label="Moderation", description="Shows all moderation commands", emoji="🚨"),
discord.SelectOption(label="Config", description="Shows all config commands", emoji="⚙️"),
discord.SelectOption(label="Games", description="Shows all meme commands", emoji="🎮")
]
# placeholder: Will be shown when no option is chosen
# options: The dropdown options which can be chosen
# min_values, max_values: Indicates that only one of the three options can be picked
super().__init__(placeholder="Choose a section", options=options, min_values=1, max_values=1)
async def callback(self, interaction: discord.Interaction):
# This function is called when the user has chosen an option
# With the interaction parameter, you can send a response message.
# With self.values you get a list of the user's selected options. We only want the first one.
await interaction.response.send_message(f"You've chosen {self.values[0]}")
#bot.command()
async def dropdown(ctx: commands.Context):
# Create a view
view = ui.View()
# Add the dropdown to this view
view.add_item(Dropdown())
# Send a message containing the view
await ctx.send(f"**Dropdown**", view=view)
If you want to disable the ui.Select you can do that with the disabled kwarg. See more in the docs.
References:
ui.Select
ui.View
discord.SelectOption
discord.Interaction

Related

Does not work Context Menus in cog - Discord.py

I wanted to create a context menu in my bot. For example, he took the documentation code.
#app_commands.context_menu(name='react')
async def react_(self, interaction: discord.Interaction, message: discord.Message):
await interaction.response.send_message('Very cool message!', ephemeral=True)
But when the code was launched in the console, the following error appeared:TypeError: context menus cannot be defined inside a class. How can I fix this?
You cannot use the decorator to create a context menu in Cogs, as explained by Danny here.
The quick way to create them in cogs is to create them by using the app_commands.ContextMenu class. Like so:
class MyCog(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
self.ctx_menu = app_commands.ContextMenu(
name='Cool Command Name',
callback=self.my_cool_context_menu, # set the callback of the context menu to "my_cool_context_menu"
)
self.bot.tree.add_command(self.ctx_menu) # add the context menu to the tree
async def my_cool_context_menu(self, interaction, message):
...
You can check out Danny's explanation for more information.

SelectMenu keeping selection after message edit

This is using the discord.py 2.0 alpha SelectMenu. After editing the original message the selections clears any idea on how to keep the selection after the edit?
I think this is how it should be done but I can't implement that in-code:
Create a variable that stores play_status_view()
Save the user choice within the object
Use the new object when editing
class play_status_view(discord.ui.View):
def __init__(self):
super().__init__(timeout=None)
#discord.ui.select(custom_id="squad_play_status", placeholder="Signup status",
min_values=1, max_values=1,
options=[discord.SelectOption(label="A"),
discord.SelectOption(label="B"),
discord.SelectOption(label="C")])
async def signup_callback(self, select: discord.ui.select, interaction: discord.Interaction):
print(select.values[0])
await interaction.response.edit_message(embed=discord.Embed(title='Test'))
# or
await interaction.response.edit_message(embed=discord.Embed(title='Test'), view=self)

Check if a user id is in a list of user ids to allow command access - discord.py

im fairly new to python and have been writing a discord bot for a server with me and a few friends as practice. I've added a few commands that could be pretty disruptive if all users had access to them at all times and have been trying to add a method to enable and disable access to them without using discord roles but a python list instead. I added a command that i can use to to add their user id to a list, but when the user tries to use the command they receive a permission error.
the code below is the problematic code from a cog
modlist = []
def ListCheck():
async def IsInList(ctx):
member = ctx.message.author.id
return member in modlist
return commands.check(IsInList)
#commands.command()
async def AddUser(self, ctx, *, question):
modlist.append(question)
#commands.command()
async def ViewModList(self, ctx):
await ctx.send('User ids that have access:')
for i in range(0, len(modlist)):
await ctx.send(modlist[i])
#commands.command()
async def ClearModList(self, ctx):
modlist.clear()
await ctx.send('Modlist cleared')
#commands.command()
#ListCheck()
async def PermTest(self, ctx):
await ctx.send('user is in modlist')
Any help would be hugely appreciated
One way you could do it would be to use commands.check(). The function in the code below checks if the message author, ctx.author, is in the given list, modList. If the author is in this list when the command 'test' is invoked, then the bot will send "You are a mod!", otherwise it will raise a check error.
modList = [394506589350002688, 697725862128386048] # just some ids as examples
def check_Mod(ctx):
if ctx.author.id in modList:
return ctx.author.id in modList
#commands.command()
#commands.check(check_Mod)
async def test(ctx):
await ctx.send("You are a mod!")
The above working is shown in the image below:
To answer is there is a way to add user ids to the list via a command?, you may either use a json or text file. In this case, I will use a text file since it's simpler, and also because my json isn't as fluent as others.
Here's an example of how your text file may look like:
394506589350002688
697725862128386048
First you need to read the file and check whether the author's id is in the file. We will be changing the check_Mod function for this. If you want to know more about reading through a text file, or feel that you may need a more efficient way, you may have a look at this: How to search for a string in text files?
def check_Mod(ctx):
with open('Mod.txt') as f: # do change the 'Mod.txt' to the name that suits you. Ensure that this file is in the same directory as your code!
if str(ctx.author.id) in f.read(): # this is reading the text file and checking if there's a matching string
return ctx.author.id
Now for writing the author id into your text file.
#commands.command()
#commands.check(check_Mod)
async def add_Mod(ctx, user:discord.Member=None):
if user == None:
await ctx.send("Please provide a user to add as a Mod!")
return
# First we'll make some functions for cleaner, more readable code #
def is_Mod(user_id):
## This function will check if the given id is already in the file. True if in file, False if not ##
with open('Mod.txt', 'r') as f:
if str(user_id) in f.read():
return True
else:
return False
def add_Mod(user_id):
## This function will add the given user id into the given text file, Mod.txt ##
with open('Mod.txt', 'a') as f: # 'a' is used for appending, since we don't want to overwrite all the ids already in the file
f.write(f"{str(user_id)}\n")
f.close()
# Now we put those functions to use #
if is_Mod(user.id) == True:
await ctx.send(f"The user {user} is already a Mod!")
else:
add_Mod(user.id)
await ctx.send(f"{user} added as a Mod!")
The above should work as seen in the image below.
p.s. If you have any other questions, please post them as a new question, thank you!

discord.py rewrite/delete standard help command

I want to make a custom !help command but I have to disable the standard one first. When I do:
client = commands.Bot(command_prefix='!')
client.remove_command('help')
Or
client = commands.Bot(command_prefix='!', help_command=None)
It still shows this message:
[1]: https://i.stack.imgur.com/Ut9dO.png
Anyone how to delete it?
A better way of making a help command is by using groups.
Firstly remove the default command;
client.remove_command("help")
After that make a help command by using this method:
#client.group(invoke_without_command= True)
async def help(ctx):
# insert your help command embed or message here
embed= discord.Embed(title="Help", description="List of commands")
embed.add_field(name="Moderation", value="!help moderation")
embed.add_field(name="Misc", value="!help misc")
await ctx.send(embed=embed)
You are done with the help command, now when you have to make help for a category or command. You can do it like this:
#help.command()
async def moderation(ctx):
embed= discord.Embed(title="Moderation", description="List of Moderation commands")
embed.add_field(name="Commands", value="ban, kick, warn, mute, unban")
await ctx.send(embed=embed)
Now if user will type, !help moderation the above embed/message will be sent.
With the recent changes in discord.py-rewrite you do not need to delete the standard help command to create your own help command. To achieve what you want you will need to subclass HelpCommand or MinimalHelpCommand, then pass it to bot.help_command.
The following code shows the standard way of subclassing MinimalHelpCommand:
class MyHelpCommand(commands.MinimalHelpCommand):
def get_command_signature(self, command):
return '{0.clean_prefix}{1.qualified_name} {1.signature}'.format(self, command)
class MyCog(commands.Cog):
def __init__(self, bot):
self._original_help_command = bot.help_command
bot.help_command = MyHelpCommand()
bot.help_command.cog = self
def cog_unload(self):
self.bot.help_command = self._original_help_command
Following the code above you will get the behaviour that you want to achieve, but if you still want to disable the default help command for any reasons, nowadays you can do it passing None to the help_command kwarg.
For more info, discord.py documentation:
https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#help-commands

Why does discord.py-rewrite bot.loop.create_task(my_background_task()) execute once but does not repeat

Using Discord.py-rewrite, How can we diagnose my_background_task to find the reason why its print statement is not printing every 3 seconds?
Details:
The problem that I am observing is that "print('inside loop')" is printed once in my logs, but not the expected 'every three seconds'. Could there be an exception somewhere that I am not catching?
Note: I do see print(f'Logged in as {bot.user.name} - {bot.user.id}') in the logs so on_ready seems to work, so that method cannot be to blame.
I tried following this example: https://github.com/Rapptz/discord.py/blob/async/examples/background_task.py
however I did not use its client = discord.Client() statement because I think I can achieve the same using "bot" similar to as explained here https://stackoverflow.com/a/53136140/6200445
import asyncio
import discord
from discord.ext import commands
token = open("token.txt", "r").read()
def get_prefix(client, message):
prefixes = ['=', '==']
if not message.guild:
prefixes = ['=='] # Only allow '==' as a prefix when in DMs, this is optional
# Allow users to #mention the bot instead of using a prefix when using a command. Also optional
# Do `return prefixes` if u don't want to allow mentions instead of prefix.
return commands.when_mentioned_or(*prefixes)(client, message)
bot = commands.Bot( # Create a new bot
command_prefix=get_prefix, # Set the prefix
description='A bot for doing cool things. Commands list:', # description for the bot
case_insensitive=True # Make the commands case insensitive
)
# case_insensitive=True is used as the commands are case sensitive by default
cogs = ['cogs.basic','cogs.embed']
#bot.event
async def on_ready(): # Do this when the bot is logged in
print(f'Logged in as {bot.user.name} - {bot.user.id}') # Print the name and ID of the bot logged in.
for cog in cogs:
bot.load_extension(cog)
return
async def my_background_task():
await bot.wait_until_ready()
print('inside loop') # This prints one time. How to make it print every 3 seconds?
counter = 0
while not bot.is_closed:
counter += 1
await bot.send_message(channel, counter)
await channel.send(counter)
await asyncio.sleep(3) # task runs every 3 seconds
bot.loop.create_task(my_background_task())
bot.run(token)
[]
From a cursory inspection, it would seem your problem is that you are only calling it once. Your method my_background_task is not called once every three seconds. It is instead your send_message method that is called once every three seconds. For intended behavior, place the print statement inside your while loop.
Although I am using rewrite, I found both of these resources helpful.
https://github.com/Rapptz/discord.py/blob/async/examples/background_task.py
https://github.com/Rapptz/discord.py/blob/rewrite/examples/background_task.py

Resources