Im currently making a help command which should show the default embed which is the fun commands page, and having a select list with the default as "Fun commands". What I want to happen is so that when I choose the select list option as "General commands", it will edit the message with the general commands embed and the same select list but with the default set to "General commands instead of "Fun commands".
if message.content.startswith('c!help'):
select = Select(
placeholder = "Choose a category",
options=[
discord.SelectOption(
label="Fun commands",
description="j"),
discord.SelectOption(
label="General commands",
description="j3")
])
view = View()
view.add_item(select)
await message.channel.send(embed=fhelp,view=view)
async def call_back(interaction):
mainthing = select.values[0]
if mainthing == "Fun commands":
await interaction.response.edit_message(embed=fhelp,view=view)
elif mainthing == "General commands":
await interaction.response.edit_message(embed=ghelp,view=view)
select.callback = call_back
Related
In my interactions.py code, I have two different bot commands. One to get information about a user's products and one to retrieve a certain product. Whenever I run my code, I get AttributeError: 'Command' object has no attribute '_options'.
This is my code:
import interactions, requests
bot = interactions.Client(token="tokenhere")
#bot.command(
name="products",
description="Get a list of all your products",
scope=scopeid,
)
#interactions.option('Your roblox UserID',name='UserID', type=interactions.OptionType.INTEGER , required=True)
#bot.command(
name="retrieve",
description="Retrieve a certain product that you own",
scope=scopeid,
options=[
interactions.Option(
name='product',
description='the product you would like to retrieve',
type=interactions.OptionType.STRING,
required=True
)
]
)
async def products(ctx: interactions.CommandContext, userid: int):
a = str(requests.get('https://jedistuff22.pythonanywhere.com/products/' + str(userid)).text)
await ctx.send(a)
async def retrieve(ctx: interactions.CommandContext, product: str):
a = ctx.author.user.username + '#' + ctx.author.user.discriminator
print(a)
await ctx.send(a)
bot.start()
For some reason, my code works when i just have one command but just flat out stops working when I have two.
I'm really stumped with this error. I have been looking online for about the past day and I am yet to find something that could help me.
You've used the same bot.command() decorator to define two bot commands. Because the bot.command() method can only define one command at a time, you must define each command separately.
import interactions
import requests
bot = interactions.Client(token="tokenhere")
#bot.command(
name="products",
description="Get a list of all your products",
scope=scopeid,
)
#interactions.option('Your roblox UserID',name='UserID', type=interactions.OptionType.INTEGER , required=True)
async def products(ctx: interactions.CommandContext, userid: int):
a = str(requests.get('https://jedistuff22.pythonanywhere.com/products/' + str(userid)).text)
await ctx.send(a)
#bot.command(
name="retrieve",
description="Retrieve a certain product that you own",
scope=scopeid,
)
#interactions.option(
name='product',
description='the product you would like to retrieve',
type=interactions.OptionType.STRING,
required=True
)
async def retrieve(ctx: interactions.CommandContext, product: str):
a = ctx.author.user.username + '#' + ctx.author.user.discriminator
print(a)
await ctx.send(a)
bot.start()
I'm trying to figure out how I can set an "expiration timer" on a message sent by a Telegram bot, containing a few buttons.
Long story short, there's a function which selects a random picture from a folder, then sends it to a group, and in a separate message it sends an InlineKeyboard object with some buttons for the picture to be rated
def send_stuff(context: CallbackContext):
job = context.job
keyboard = [
[
InlineKeyboardButton("NEVER", callback_data="NEVER"),
InlineKeyboardButton("UNLIKELY", callback_data="UNLIKELY")
],
[
InlineKeyboardButton("MEH", callback_data="MEH"),
InlineKeyboardButton("MAYBE", callback_data="MAYBE")
],
[
InlineKeyboardButton("YES", callback_data="YES"),
InlineKeyboardButton("ABSOLUTELY", callback_data="ABSOLUTELY")
],
[
InlineKeyboardButton("RATHER NOT SAY", callback_data="UNKNOWN")
]
]
reply_markup = InlineKeyboardMarkup(keyboard)
context.bot.send_photo(job.context, photo=open(PATH+thefile, 'rb'))
context.bot.send_message(job.context, text='RATE', reply_markup=reply_markup)
This function is being run by a run_daily job:
def start(update: Update, context: CallbackContext):
job = context.job
chat_id = update.message.chat_id
context.job_queue.run_daily(
send_stuff,
datetime.time(13, 45, 00, 000000, tzinfo=pytz.timezone('Europe/Bucharest')),
days=tuple(range(7)),
context=chat_id,
name='j1'
)
Then there is a handler for the user input, which edits the last message sent by the bot:
def main_handler(update: Update, context: CallbackContext):
update.callback_query.answer()
if update.callback_query.data is not None:
user_input = update.callback_query.data
update.effective_message.edit_text('VERDICT: ' + user_input)
What I'm trying to do is set some kind of "expiration" on the message containing the inline keyboard buttons, such that if there is no click by a user in say... 4 hours, it automatically edits itself into something like "NO ANSWER GIVEN".
I'm not super experienced with bots, and looking through the documentation of the telegram bot libraries I have not been able to find a way to do it.
Any suggestions are appreciated.
Thanks!
You apparently already know how to use PTBs JobQueue, so I'm sure that you can figure out how to schedule a new job from within the send_stuff function that edits the sent message :) All you need for that is context.job_queue.run_once and the return value of context.bot.send_message(job.context, text='RATE', reply_markup=reply_markup).
Disclaimer: I'm currently the maintainer of python-telegram-bot.
Thanks to user #CallMeStag I implemented the following solution.
def send_stuff(context: CallbackContext):
job = context.job
keyboard = [
[
InlineKeyboardButton("NEVER", callback_data="NEVER"),
InlineKeyboardButton("UNLIKELY", callback_data="UNLIKELY")
],
[
InlineKeyboardButton("MEH", callback_data="MEH"),
InlineKeyboardButton("MAYBE", callback_data="MAYBE")
],
[
InlineKeyboardButton("YES", callback_data="YES"),
InlineKeyboardButton("ABSOLUTELY", callback_data="ABSOLUTELY")
],
[
InlineKeyboardButton("RATHER NOT SAY", callback_data="UNKNOWN")
]
]
reply_markup = InlineKeyboardMarkup(keyboard)
context.bot.send_photo(job.context, photo=open(PATH+thefile, 'rb'))
# return values of send_message are saved in the 'msg' var
msg context.bot.send_message(job.context, text='RATE', reply_markup=reply_markup)
# the following job is created every time the send_stuff function is called
context.job_queue.run_once(
callback=cleanup,
when=5,
context=msg,
name='cleanup'
)
# the function called by the job
def cleanup(context: CallbackContext):
job = context.job
context.bot.edit_message_text(
chat_id=job.context.chat.id,
text='NO ANSWER PROVIDED',
message_id=job.context.message_id
)
How to add role by name not id. group is string
await message.author.add_roles(message.author, group)
You can use discord.utils.get function for this:
role_name = "role" # specify role name here
role = discord.utils.get(message.guild.roles, name=role_name)
if role is not None:
await message.author.add_roles(role)
so right now I am trying to create a command which allows the user to modify their channel's details on an embed. The only problem I have here is that I need to manually specific a number for where the embed field is. Is there a way for the bot to scan through the whole embed for a specific name and return the fields position? (I have a example linked below)
message = guild.get_message(63861098570842132)
embed = next(embed for embed in message.embeds)
embed.fields[0].value = "New value" #Issue Here
await message.edit(embed=embed)
https://gyazo.com/967101d666e78dcccef945f3c5d6e280 >Example of the embed
Get the embed in form of a dict, loop through every field and if it's the field you want, simply change it's value. Then convert the dict to a discord.Embed obj and edit the message
# This is the user input
user_input = {'field name': 'some name', 'field value': 'some value'}
# Getting the embed and converting it to a dict
embed = message.embeds[0]
embed_dict = embed.to_dict()
for field in embed_dict['fields']:
if field['name'] == user_input['field name']:
field['value'] = user_input['field value']
# Converting the embed to a `discord.Embed` obj
edited_embed = discord.Embed.from_dict(embed_dict)
# Editing the message
await message.edit(embed=edited_embed)
Reference:
discord.Embed.to_dict
discord.Embed.from_dict
message.edit
I'm trying to use lower() so the role names are not case sensitive. So if a user types lol instead of LoL it won't go through the if statement if not role_id:
This is how I'm doing it:
#commands.command()
#commands.check(lambda ctx: ctx.channel.id in [555844758778544160])
async def add(self, ctx, *, rolename):
author = ctx.message.author
role_dict = {
"Members":557212810468392970,
"PS4":568761643916328960,
"LoL":559792606364565505}
role_id = role_dict.get(rolename.lower())
if not role_id:
await ctx.send("I cannot find the role {}.".format(rolename))
return
role = discord.utils.get(ctx.message.guild.roles, id = role_id)
message = '{} added the role **{}**'.format(author.display_name, role.name)
embed = discord.Embed(description=message.format(author.display_name, role.name), colour=0xff0000)
await author.add_roles(role)
await ctx.send("Role Added")
This line here role_id = role_dict.get(rolename.lower()) is the culprit when I add the role !add lol rather than LoL this is what I'm getting:
Help much appreciated.
The problem is that you're comparing a lowercase rolename with dictionary keys that are not in lowercase. For a case-insensitive check, both the rolename and dictionary keys should be lowercase.
Either manually change the dictionary keys to lowercase:
role_dict = {
"members":557212810468392970,
"ps4":568761643916328960,
"lol":559792606364565505}
Or create it programmatically with a dict comprehension, and check if rolename.lower() is in the lowercase dict:
role_dict = {
"Members":557212810468392970,
"PS4":568761643916328960,
"LoL":559792606364565505}
lowercase_dict = {k.lower():v for k,v in role_dict.items()}
role_id = lowercase_dict.get(rolename.lower())
if not role_id:
await ctx.send("I cannot find the role {}.".format(rolename))
return