everyone having a small issue with the Slash commands.
The idea is that I fetch an Array of Assetdata convert each into an embedded and then send the embedded. If there is an image it will show an image and if a .mp4 is linked to the asset it will convert the mp4 to gif and then attache the file locally with file = discord.File(). This all worked just fine bevor moving to Slash commands. For some reason, the slash command wants to send a response bevor receiving all the data. This is an issue because the gif processing takes time or if a large sum of data is requested the request takes longer. The function works fine if have a single asset to display and an Image.
So my question is how do I get ctx.send() to wait??
Thanks in Advance everyone!
client = commands.Bot(command_prefix = "!")
slash = SlashCommand(client, sync_commands=True)
#slash.slash(
name="assetsearch",
description="Sends a Message",
guild_ids=[XXXXXXXXXXXXXXXX], #Hidden for StackOverflow
options = [
create_option(
name = "searchtype",
description = "Please choose how you would like to search for an Asset.",
required = True,
option_type = 3,
choices = [
create_choice(
name = "Search by Asset Id",
value = "id"
),
create_choice(
name = "Search by Collection",
value = "colec"
),
create_choice(
name = "Search by Accountname",
value = "acc"
),
create_choice(
name = "Search by Asset Name",
value = 'match'
)
]
),
create_option(
name = "searchterm",
description = "Please enter an Asset Id, an Account name, the name of an Asset or the Collection name.",
required = True,
option_type = 3
),
create_option(
name = "amount",
description = "Please enter how many Assets you would like to display.",
required = True,
option_type = 3
),
],
)
async def _assetsearch(ctx:SlashContext, searchtype: str, searchterm: str, amount: str):
response = await getAssetData(searchtype, searchterm, amount) #Fetches an Array of AssetData, async function
for asset in response:
nftEmbed, nftFile = await __formatMessage(asset) #formats the message, converts mp4 from website to gif, returns the gif and ebeded
print(nftEmbed,nftFile)
await ctx.send(embed=nftEmbed, file=nftFile) #send the embeded and gif, ISSUE!!!
if os.path.isfile('Nft.gif'): os.remove("Nft.gif")
response = ""
Working Function bevor using slash-command
if msg.startswith('$search'):
try:
searchType = msg.split(",")[1]
except:
searchType = 'match'
try:
searchTerm = msg.split(",")[2]
except:
searchTerm = 'abcd'
try:
searchLimit = msg.split(",")[3]
except:
searchLimit = '1'
response = getAssetData(searchType,searchTerm,searchLimit)
for asset in response:
nftEmbed, file = __formatMessage(asset)
await message.channel.send(embed=nftEmbed, file=file)
if os.path.isfile('Nft.gif'): os.remove("Nft.gif")
response = ""
I figured it out. The Slashcomands are expecting a response within 3s if you are working with an API in the background and then precessing data this could become a criterium you cant meet consistently. This is why you would have the Bot itself respond directly upon request. Once you are done with processing your data you can respond normaly
async def _slashcomandfunction(ctx:SlashContext, str:otherparameters,):
message = await ctx.send('Sometext') #Direct respond
await ctx.channel.send(embed=embed, file=file) #Actual message
If you don't want the Bots message
message = await ctx.send('Sometext',delete_after=1)
...or edit the message the Bot sent.
message = await ctx.send('Sometext')
await message.edit(content="newcontent")
Can't you just use asyncio?
import asyncio
await asyncio.sleep(number)
Or is this not what you are looking for?
Related
I am trying to get images from User on telegram bot.
Before that, getting some information from the user (using bot.register_next_step_handler).
Example code:
def admin_panel_add_sneakers_type (message):
sneakers_type = message.text
message_text = 'Send sneakers price:'
msg = bot.send_message(message.chat.id, message_text)
bot.register_next_step_handler(msg, admin_panel_add_sneakers_price, sneakers_type )
def admin_panel_add_sneakers_price (message, sneakers_type):
sneakers_price = message.text
message_text = 'Send sneakers count:'
msg = bot.send_message(message.chat.id, message_text)
bot.register_next_step_handler(msg, admin_panel_add_sneakers_count, sneakers_type, sneakers_price )
After that, I'm trying to get photos of sneakers from the user
def admin_panel_add_sneakers_to_db(message, sneakers_type, sneakers_price, sneakers_count):
if message.content_type == 'photo':
fileID = message.photo[-1].file_id
file_info = bot.get_file(fileID)
downloaded_file = bot.download_file(file_info.file_path)
message.photo contains an array of one photo (the first image of several sended by the user) of different quality, but how i can get all photos?
Also, i saw this method for solve my problem - #bot.message_handler(content_types=['photo'])
But I need to remember the user's choice, before send photos - sneakers_type, sneakers_price, sneakers_count
I'm trying to use the TGRCode API to make a Discord command which returns information about a level in Super Mario Maker 2. However, I'm running into a problem.
If the level has no, for example, Clear Condition, then it throws a Key Error and stops the command. I know what it does that, because it just isn't present in the JSON that the API returns, and not as a empty string or anything.
However, the problem is that I am not sure how to deal with it.
(I am trying to receive the information using AIOHTTP)
I have tried using
if clear_condition == None:
clear_condition = "None"
That just returns a KeyError
I have also tried
if clear_condition_name not in response:
clear_condition_name = "None"
That just returns an error saying ClientResponse is not iterable.
I tried (with and without the quotation marks)
if "clear_condition_name" not in response.json():
clear_condition_name = "None"
And that just spits out another Key Error.
I have also checked this article by Career Karma, but it does not help as I am not the one defining the dictionary.
Here is my current code:
#commands.command()
async def smm2_lookup_level(self, ctx, code):
await ctx.reply(f"Getting level information of level with code `{code}`")
print(f"{ctx.author.name} has requested to get all information for {code}.")
MAIN = f"https://tgrcode.com/mm2/level_info/{code}"
async with request("GET", MAIN, headers={}) as response:
if response.status == 200:
print("The TGRCode API returned OK; getting info...")
data = await response.json()
title = data["name"]
description = data["description"]
upload_date = data["uploaded_pretty"]
course_id = data["course_id"]
style = data["game_style_name"]
theme = data["theme_name"]
difficulty = data["difficulty_name"]
tags = data["tags_name"]
upload_time = data["upload_time_pretty"]
number_of_comments = data["num_comments"]
clear_condition_name = data["clear_condition_name"]
clear_condition_magnitude = data["clear_condition_magnitude"]
clears = data["clears"]
attempts = data["attempts"]
clear_rate = data["clear_rate"]
plays = data["plays"]
likes = data["likes"]
boos = data["boos"]
thumbnail = f"https://tgrcode.com/mm2/level_thumbnail/{code}"
map = f"https://tgrcode.com/mm2/level_entire_thumbnail/{code}"
if clear_condition_name not in response.json():
clear_condition_name = "None"
clear_condition_magnitude = ""
if "clear_condition_magnitude" not in response.json():
clear_condition_name = "None"
clear_condition_magnitude = ""
if "description" not in response.json():
description = ""
if "tags" not in response.json():
tags = "None"
embed = discord.Embed(title="SMM2 Level Information.")
embed.add_field(name="Level Name", value=title, inline=True)
embed.add_field(name="Level Description", value=description, inline=True)
embed.add_field(name="Level Code", value=course_id, inline=True)
embed.add_field(name="Level Style", value=style, inline=True)
embed.add_field(name="Level Theme", value=theme, inline=True)
embed.add_field(name="Level Difficulty", value=difficulty, inline=True)
embed.add_field(name="Tags", value=tags, inline=True)
embed.add_field(name="Upload Date", value=upload_date, inline=True)
embed.add_field(name="Time taken to Clearcheck Course", value=upload_time, inline=True)
embed.add_field(name="Clear Condition Information", value=f"{clear_condition_name} {clear_condition_magnitude}.", inline=True)
embed.add_field(name="Clear Information", value=f"Clears: {clears}\nAttemps: {attempts}\nPlays: {plays}\nClear Rate: {clear_rate}.")
embed.add_field(name="Number of Comments", value=number_of_comments, inline=True)
embed.set_thumbnail(url=thumbnail)
embed.set_image(url=map)
embed.add_field(name="Like:Boo Ratio", value=f"{likes}:{boos}")
await ctx.send(f"{ctx.author.mention} Here's the information for level with code `{code}`:", embed=embed)
else:
await ctx.send(f"I was unable to retrieve the information. Try again, if not the TGRCode API may be down, or there is an error on my end.\n*Response Status: {response.status}*")
print(f"I was unable to retrieve the information from TGRCode.\n*Response Status: {response.status}*")
So, with all of what I have tried resulting in no help, I'm hoping I can find some here.
Thanks.
The problem is you are trying to read that key when you declare the clear_condition_name variable. You should check if the response data dictionary has such a key, like this:
clear_condition_name = data["clear_condition_name"] if "clear_condition_name" in data.keys() else "None"
I'm new to python and i'm making discord bot. So here i have twitch notification function, but when someone is live bot just starts spamming, i think because idk how to get content out of an embed. please help me. the code:
import os
import json
import discord
import requests
from discord.ext import tasks, commands
from discord.utils import get
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='$', intents=intents)
TOKEN = os.getenv('token')
# Authentication with Twitch API.
client_id = os.getenv('client_id')
client_secret = os.getenv('Dweller_token')
body = {
'client_id': client_id,
'client_secret': client_secret,
"grant_type": 'client_credentials'
}
r = requests.post('https://id.twitch.tv/oauth2/token', body)
keys = r.json()
headers = {
'Client-ID': client_id,
'Authorization': 'Bearer ' + keys['access_token']
}
'''user_info = twitch.get_users(logins=['turb4ik'])
user_id = user_info['data'][0]['id']
print(user_info)'''
# Returns true if online, false if not.
def checkuser(streamer_name):
stream = requests.get('https://api.twitch.tv/helix/streams?user_login=' + streamer_name, headers=headers)
stream_data = stream.json()
if len(stream_data['data']) == 1:
return True, stream_data
else:
return False, stream_data
# Executes when bot is started
#bot.event
async def on_ready():
# Defines a loop that will run every 10 seconds (checks for live users every 10 seconds).
#tasks.loop(seconds=10)
async def live_notifs_loop():
# username = stream_data['data'][0]['user_name']
# stream_title = stream_data['data'][0]['title']
# game_being_played = stream_data['data'][0]['game_name']
# Opens and reads the json file
with open('streamers.json', 'r') as file:
streamers = json.loads(file.read())
# Makes sure the json isn't empty before continuing.
if streamers is not None:
# Gets the guild, 'twitch streams' channel, and streaming role.
guild = bot.get_guild(690995360411156531)
channel = bot.get_channel(798127930295058442)
role = get(guild.roles, id=835581408272580649)
# Loops through the json and gets the key,value which in this case is the user_id and twitch_name of
# every item in the json.
for user_id, twitch_name in streamers.items():
print("checking" + " " + str(twitch_name))
# Takes the given twitch_name and checks it using the checkuser function to see if they're live.
# Returns either true or false.
status, stream_data = checkuser(twitch_name)
# Gets the user using the collected user_id in the json
user = bot.get_user(int(user_id))
# Makes sure they're live
if status is True:
# Checks to see if the live message has already been sent.
async for message in channel.history(limit=200):
print("yes")
twitch_embed = discord.Embed(
title=f":red_circle: **LIVE**\n{user.name} is now streaming on Twitch! \n \n {stream_data['data'][0]['title']}",
color=0xac1efb,
url=f'\nhttps://www.twitch.tv/{twitch_name}'
)
twitch_embed.add_field(
name = '**Game**',
value = stream_data['data'][0]['game_name'],
inline = True
)
twitch_embed.add_field(
name = '**Viewers**',
value = stream_data['data'][0]['viewer_count'],
inline = True
)
twitch_embed.set_author(
name = str(twitch_name),
icon_url = stream_data['data'][0]['thumbnail_url']
)
twitch_embed.set_image(url = f'https://www.twitch.tv/{twitch_name}')
print("yes2")
try:
embed_title = twitch_embed.title
embed_description = twitch_embed.description
except Exception as e:
break
print("yes3")
# If it has, break the loop (do nothing).
if embed_title == True:
break
# If it hasn't, assign them the streaming role and send the message.
else:
# Gets all the members in your guild.
async for member in guild.fetch_members(limit=None):
# If one of the id's of the members in your guild matches the one from the json and
# they're live, give them the streaming role.
if member.id == int(user_id):
await member.add_roles(role)
# Sends the live notification to the 'twitch streams' channel then breaks the loop.
await channel.send(
content = f"Hey #everyone! {user.name} is now streaming on Twitch! Go check it out: https://www.twitch.tv/{twitch_name}", embed=twitch_embed)
print(f"{user} started streaming. Sending a notification.")
break
# If they aren't live do this:
else:
# Gets all the members in your guild.
async for member in guild.fetch_members(limit=None):
# If one of the id's of the members in your guild matches the one from the json and they're not
# live, remove the streaming role.
if member.id == int(user_id):
await member.remove_roles(role)
# Checks to see if the live notification was sent.
async for message in channel.history(limit=200):
try:
embed_title = message.embeds[0].title
embed_description = message.embeds[0].description
except Exception as e:
break
# If it was, delete it.
if user.mention in embed_title and "is now playing" in embed_title:
print(f"{user} stopped streaming. Removing the notification.")
await message.delete()
# Start your loop.
live_notifs_loop.start()
# Command to add Twitch usernames to the json.
#bot.command(name='addtwitch', help='Adds your Twitch to the live notifs.', pass_context=True)
async def add_twitch(ctx, twitch_name):
# Opens and reads the json file.
with open('streamers.json', 'r') as file:
streamers = json.loads(file.read())
# Gets the users id that called the command.
user_id = ctx.author.id
# Assigns their given twitch_name to their discord id and adds it to the streamers.json.
streamers[user_id] = twitch_name
# Adds the changes we made to the json file.
with open('streamers.json', 'w') as file:
file.write(json.dumps(streamers))
# Tells the user it worked.
await ctx.send(f"Added {twitch_name} for {ctx.author} to the notifications list.")
print('Server Running')
bot.run(TOKEN)
Just for others context, he had shown me the error on discord, so I am answering him through this question!
So mate, I found the error.
The line 106 in your code is:
await message.channel.send(msg)
Now this msg variable send all the details but we just want the content of it and not anything else.
So change that to:
await message.channel.send(msg.content)
Thank You! :D
I was wondering if i can make input() using TeleBot dependency.
e.g. console way:
POL = float(input("Enter your POL: ))
Is there a way to do using Telebot, like:
bot.send_message(message.chat.id, "Enter your POL")
## Get message.text into POL variable.
From what I understand, there isn't a direct way of doing this, but you can look at the message that the user has replied to from
replied_message = message.reply_to_message.message_id
If it matches the id of the message that you sent then that would be the reply to your message. You can get the id of your sent message from
sent_message = bot.send_message(message.chat.id, "Enter your POL")
sent_message_id = sent_message.message_id
import telebot
TELEGRAM_TOKEN = '<TOKEN>'
bot = telebot.TeleBot(TELEGRAM_TOKEN)
user_register_dict = {}
#bot.message_handler(commands=['start'])
def start(message):
bot.reply_to(message , 'now send your name')
user_register_dict[message.chat.id] = {}
bot.register_next_step_handler(message , start_step2)
def start_step2(message):
user_register_dict[message.chat.id]['name'] = message.text
bot.reply_to(message , 'now send your age')
bot.register_next_step_handler(message , start_step3)
def start_step3(message):
user_register_dict[message.chat.id]['age'] = message.text
bot.reply_to(message , 'your name is {} and you are {} years old!'
.format(user_register_dict[message.chat.id]['name'] ,
[message.chat.id]['age'] ))
start(message = message)
Create a dict for handling the data, which is important because if you use lists (eg.) maybe 2 people starts to register in same time and data gonna crash!
Difference between create bot.register_next_step_handler (line 13 for example) with connect directly for example start(message = message) in end line is in register_next_step_handler bot waits for new message and when received puts it in message and start defection but in direct start defection bot doesn't wait for user message, and start defection with current message start(message = message)
I've been developing a Discord bot with discord.py for a while and have found myself frequently using embeds and setting their images with the set_image() function to access image data from various sites. for example:
embed.set_image(url='https://img.pokemondb.net/artwork/large/{}.jpg'.format(pokemon.name.lower()))
to set the image to that of the requested pokemon.
My most recent endeavor has been to create a command to display a Minecraft player's skin/head given their username. My code:
#bot.group(pass_context = True, aliases = ['minecraft'])
async def mc(ctx):
if ctx.invoked_subcommand is None:
embed = discord.Embed(
title = 'Error!',
description = ':x: Please specify a subcommand!',
color = 10891826
)
await bot.say(embed = embed)
#mc.command()
async def head(username = None):
if username is None:
embed = discord.Embed(
title = 'Error!',
description = ':x: Head not found! Did you spell the username right? It is case-sensitive.',
color = 10891826
)
await bot.say(embed = embed)
else:
http_conn = http.client.HTTPSConnection("api.mojang.com")
http_conn.request("GET", "/users/profiles/minecraft/" + username,
headers={'User-Agent':'Minecraft Username -> UUID', 'Content-Type':'application/json'})
response = http_conn.getresponse().read().decode("utf-8")
if (not response):
return ""
json_data = json.loads(response)
try:
uuid = json_data['id']
except KeyError as e:
print("KeyError raised:", e)
embed = discord.Embed(
title = 'Head of {}'.format(username),
color = 53380
)
embed.set_image(url = 'https://crafatar.com/avatars/{}.jpg'.format(uuid))
await bot.say(embed = embed)
#mc.command()
async def skin(username = None):
if username is None:
embed = discord.Embed(
title = 'Error!',
description = ':x: Skin not found! Did you spell the username right? It is case-sensitive.',
color = 10891826
)
await bot.say(embed = embed)
else:
http_conn = http.client.HTTPSConnection("api.mojang.com")
http_conn.request("GET", "/users/profiles/minecraft/" + username,
headers={'User-Agent':'Minecraft Username -> UUID', 'Content-Type':'application/json'})
response = http_conn.getresponse().read().decode("utf-8")
if (not response):
return ""
json_data = json.loads(response)
try:
uuid = json_data['id']
except KeyError as e:
print("KeyError raised:", e)
embed = discord.Embed(
title = 'Skin of {}'.format(username),
color = 53380
)
embed.aet_image(url = 'https://crafatar.com/renders/body/{}.jpg'.format(uuid))
await bot.say(embed = embed)
Everything works fine for some usernames, but for others, the image simply doesn't show up. Some odd cases even work for the head command but not the skin command (or vice versa). I've noticed after much experimenting that swapping the extension from .jpg to .png fixes the issue for the ones that don't work, and stop the ones that previously worked from working. Inputting the values manually into the crafatar site (with any extension or even with no extension at all) yields a valid direct image link, but for some reason, it won't load into the embed. It doesn't give me any error or exception, so I can't solve this by excepting and changing it to .png in the except statement, leaving me lost. If anyone knows why this is happening or what I can do to fix it, I'll be very grateful. I'm probably just being stupid but I've spent way too long on this, all I've dug up online are people forgetting to use kwargs (ie set_image('url') rather than set_image(url='url'), and it's making my brain hurt.
Note: I am not using the rewrite version of discord.py and I don't intend to port my entire bot over to it so please don't suggest that