Facing issues with a discord.py "hug command" - python

I am currently making a Discord.py bot that responds to commands with a random image that has been specified, here is my code:
hug_gifs = ['https://c.tenor.com/nHkiUCkS04gAAAAC/anime-hug-hearts.gif']
hug_names = ['Hugs you!']
#bot.command()
async def hug(ctx):
embed = discord.Embed [
colour=(discord.Colour.red()).
description = f"{ctx.author.mention} {(random.choice(hug_names))}"
)
embed.set_image(url=(random.choice(hug_gifs)))
await ctx.send(embed = embed)

There are two mistakes when you are trying to create the discord.Embed:
When passing the arguments to the discord.Embed object, you are starting the initializer with a [, which should be changed to (. In Python the [ and ] shall be used only to create a list or to reference any of its positions.
You are using a dot . as separator for the different arguments taken by the constructor of discord.Embed, but that should be a comma , .
Here is your corrected code:
hug_gifs = ['https://c.tenor.com/nHkiUCkS04gAAAAC/anime-hug-hearts.gif']
hug_names = ['Hugs you!']
#bot.command()
async def hug(ctx):
embed = discord.Embed (
colour=(discord.Colour.red()),
description = f"{ctx.author.mention} {(random.choice(hug_names))}"
)
embed.set_image(url=(random.choice(hug_gifs)))
await ctx.send(embed = embed)

Related

loop attribute cannot be acessed in non-async contexts with discord.py

When I try to run this code
`
import json
import os
import random
from pprint import pprint
import aiohttp
import discord
import requests
from discord.ext import commands
from dotenv import load_dotenv
from mojang import api
# Functions
# Sends a Get request to a given url
def get_info(call):
r = requests.get(call)
return r.json()
# Get the sum of coins in the bazaar
def get_bazaar_buy_order_value(bazaar_data):
sum_coins = 0
price_increase_threshold = 2
buy_order_values = []
# For every product
for item_name, item_data in bazaar_data.get("products", {}).items():
item_sum_coins = 0
# For every buy order
for idx, buy_order in enumerate(item_data.get("buy_summary", [])):
# If its the best price
if(idx == 0):
item_expected_value = buy_order.get("pricePerUnit", 0)
item_sum_coins += buy_order.get("amount", 0) * buy_order.get("pricePerUnit", 0)
# If its not the best price, check for reasonable price
else:
if(buy_order.get("pricePerUnit", 0) < (item_expected_value * price_increase_threshold)):
item_sum_coins += buy_order.get("amount", 0) * buy_order.get("pricePerUnit", 0)
buy_order_values.append((item_name, item_sum_coins))
sum_coins += item_sum_coins
sort_bazaar_buy_orders_by_value(buy_order_values)
return sum_coins
# Sorts and displays a list of buy order items by total value
def sort_bazaar_buy_orders_by_value(buy_order_values):
# Sort items by values
buy_order_values.sort(key = lambda x: -x[1])
# Display items and values
for (item_name, item_sum_coins) in buy_order_values:
print(f"{item_name.ljust(30, ' ')} | {round(item_sum_coins):,}")
return
# Returns Bazaar data
def get_bazaar_data():
return get_info("https://api.hypixel.net/skyblock/bazaar")
# Returns a specific item from the Bazaar
def get_bazaar_item():
return
# Returns auction info from player uuid
def get_auctions_from_player(uuid):
return get_info(f"https://api.hypixel.net/skyblock/auction?key={API_KEY}&player={uuid}")
# Returns current mayor/election data
def get_election_data():
return get_info(f"https://api.hypixel.net/resources/skyblock/election")
# Returns a list of player profiles
def get_profiles_data():
return get_info(f"https://sky.shiiyu.moe/api/v2/profile/{example_uuid}")
# Returns player UUID when prompted with the name
async def get_uuid(name):
return get_info(f"https://sky.shiiyu.moe/api/v2/profile/{name}")
# Discord Functions / Vars
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
GUILD = os.getenv('DISCORD_GUILD')
client = discord.Client(intents=discord.Intents.default())
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='/',intents=intents)
# Hypixel Vars
Item = "Diamond"
API_FILE = open("API_KEY.json","r")
example_name = "4748"
example_uuid = "147ab344d3e54952b74a8b0fedee5534"
uuid_dashed = "147ab344-d3e5-4952-b74a-8b0fedee5534"
API_KEY = json.loads(API_FILE.read())["API_KEY"]
example_player_uuid = "147ab344d3e54952b74a8b0fedee5534"
auctions_player_url = f"https://api.hypixel.net/skyblock/auction?key={API_KEY}&player={example_player_uuid}"
# Commands
#bot.command(name='bazaar', description = "Gives a detailed readout of a certain item in the bazaar", brief = "Get data of an item in bazaar")
async def bazaar(ctx):
await ctx.send(get_bazaar_data())
await ctx.send(API_KEY)
#bot.command(name="bazaartotal", description = "Show the total amount of coins on the bazaar at any given point", brief = "Shows the amount of coins in the bazaar")
async def baztot(ctx):
await ctx.send(get_bazaar_buy_order_value(get_bazaar_data()))
#bot.command(name = "apikey", description = "Gives 4748's API key, make sure to remove me once publicly availible!", brief = "API Key")
async def key(ctx):
await ctx.send(API_KEY)
#bot.command(name = "profiles", description = 'Get a list of player profiles and data about them', brief = "List player profiles")
async def prof(ctx):
await ctx.send("Username to check?")
message = client.wait_for('message', check=lambda m: m.user == ctx.user)
username = str(message.content)
uuid = get_uuid(username)
pprint(uuid)
await ctx.send(uuid)
bot.run(TOKEN)
I get this error
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: loop attribute cannot be accessed in non-async contexts. Consider using either an asynchronous main function and passing it to asyncio.run or using asynchronous initialisation hooks such as Client.setup_hook
Anyone have a fix for this? The bot runs normally, but once I try to run /profiles it gives me that error. Also, other commands work fine, but when I try to access an api with a
Changed my code multiple times, putting the get_uuid command in async, and googling for a few hours. any help is appreciated!
Your Bot variable is called bot, but you're using client in your wait_for statement.
You've got both a discord.Client ("client") and a commands.Bot ("bot") instance. This doesn't make a whole lot of sense. If you only need Client features then use Client, if you want Bot features then use Bot. You can't use both at the same time.
Also, wait_for is a coroutine, so you should await it.
# Yours:
message = client.wait_for('message', check=lambda m: m.user == ctx.user)
# ^^^^^^^
# Missing await keyword & wrong bot variable
# Correct:
message = await bot.wait_for(...)
# ^^^^^ ^^^
Docs: https://discordpy.readthedocs.io/en/stable/api.html?highlight=wait_for#discord.Client.wait_for
PS requests is blocking and will make your whole bot freeze. Consider looking into an asynchronous http library like aiohttp.
try to do this:
message = await client.wait_for('message', check=lambda m: m.user == ctx.user)
I advise you to remove the 'name' from the slash command argument, it's better to just name the function and add an additional check for the channel 'm.channel == ctx.channel' to wait_for and split the file into several

Can I use an f string to design a url for my discord.py bot's embeds' images?

I'm creating a command for a discord bot and I want it to be able to send me an animated sprite from the Pokemon Showdown website.
#client.command()
async def dex(ctx, args):
args_l = args.lower()
if "," in args_l:
args_split = args_l.split()
pokemon = args_split[1]
url = "https://media2.giphy.com/media/3oEjI6SIIHBdRxXI40/200.gif"
tag = args_split[0]
if tag == "shiny":
url = f"play.pokemonshowdown.com/sprites/ani-shiny/{pokemon}.gif"
elif tag == "mega":
url = f"play.pokemonshowdown.com/sprites/xyani/{pokemon}-mega.gif"
else:
url = f"play.pokemonshowdown.com/sprites/xyani/{pokemon}.gif"
embed = discord.Embed(title="POKEDEX", color=c, timestamp=datetime.datetime.now())
embed.set_footer(text="Pokedex")
embed.description = f"Pokemon: {pokemon}\n\nApplicable Tags: {tag}\n\nThis auction has increments of {increment}\n\nAutobuy: {ab}"
embed.set_image(url=url)
await ctx.send(embed=embed)
When I run this command, dex, my bot does not send an embed (await ctx.send(embed=embed) isn't sending an embed). There is no error message. When I try using a command that isn't added to the bot, it responds with a message, "I do not have this command" (which I set it to do with a CommandNotFound error checker).
I think the problem is either in the urls or the embed.set_image(url=url).
You are trying to send pokemon, tag, ab, and increment variables even though they are not set when there is no ',' in args, also the urls have to have 'https://' at the front for it to work. Something like this seems to work but then again you need to make sure you cover the case where there is no ',' in args.
#client.command()
async def dex(ctx, args):
pokemon = args
args_l = args.lower()
if "," in args_l:
args_split = args_l.split(',')
pokemon = args_split[1]
url = "media2.giphy.com/media/3oEjI6SIIHBdRxXI40/200.gif"
tag = args_split[0]
if tag == "shiny":
url = f"play.pokemonshowdown.com/sprites/ani-shiny/{pokemon}.gif"
elif tag == "mega":
url = f"play.pokemonshowdown.com/sprites/xyani/{pokemon}-mega.gif"
else:
url = f"play.pokemonshowdown.com/sprites/xyani/{pokemon}.gif"
embed = discord.Embed(
title="POKEDEX", color=discord.Colour.random(), timestamp=datetime.datetime.now())
embed.set_footer(text="Pokedex")
embed.description = f"Pokemon: {pokemon}\n\nApplicable Tags: {tag}\n\nThis auction has increments of \n\nAutobuy: "
embed.set_image(url="https://"+url)
await ctx.send(embed=embed)
Without an error message, it is difficult to know for sure, but it looks like this is your problem:
If there is no , in your command, the pokemon variable is unset when you try to use it in url = f"play.pokemonshowdown.com/sprites/xyani/{pokemon}.gif"
It looks like you need to modify the else block to something like the following:
else:
pokemon = args_l
url = f"play.pokemonshowdown.com/sprites/xyani/{pokemon}.gif"
You also need to specify what character you're splitting with earlier on in the function, as str.split() without any argument splits on whitespace rather than a comma which appears to be what you want:
args_split = args_l.split(",")

How to words in list in an embed | discordpy?

I want to show the words I have in a list to the user, I have used the 'for' loop but this loop sends as many messages as all the words in the list
For example: 3 words are in a list, I want to send these three words once but it sends three times
code :
#commands.command(name="showwords")
async def showwords(self,context):
if context.message.author.guild_permissions.administrator:
for word in config.WORDS:
NOW_WORD = "\n".join(config.WORDS)
embed = discord.Embed(
title="**Forbidden words :**",
description=f"||{NOW_WORD}||\n",
color=0x00FF00,
)
embed.set_footer(
text=f"Requested by {context.message.author}"
)
embed_message = await context.send(embed=embed)
await embed_message.add_reaction("📃")
else:
embed = discord.Embed(
title="Error!",
description="You don't have the permission to use this command.",
color=0x00FF00,
)
embed_message = await context.send(embed=embed)
await embed_message.add_reaction("⛔")
i think it is because
NOW_WORD = "\n".join(config.WORDS)
here you are combining all the words into the NOW_WORD
instead of assigning a "NOW_WORD" you should be able to use "word" in the for loop as "NOW_WORD".

Getting emoji object to unicode

Right now im my journey of discordbot making, I'm tackling reaction roles! I think I have most everything setup, but I can't seem to find a way to get from an emoji object to an emoji unicode, so I can compare them and add the reaction. Here's what I have so far:
#bot.event
async def on_raw_reaction_add(payload):
print(payload)
channel = bot.get_channel(payload.channel_id)
emoji = payload.emoji
print(emoji.id)
#bot.command(pass_context=True)
async def reactionrole(ctx, title:str, description:str, name:str, value:str):
title = ''.join(title)
description = ''.join(description)
name = ''.join(name)
value = ''.join(value)
embed = discord.Embed(colour = discord.Colour.teal(), title = title, description = description)
embed.add_field(name = name, value = value, inline=False)
message = await ctx.send(embed = embed)
with open("reactionroles.json", 'r') as f:
data = json.load(f)
addon = {"guild-id" : ctx.guild.id}, {"message-id" : message.id}, {"roles" : []}, {"emojis" : []}
data[ctx.guild.id] = addon
with open("reactionroles.json", 'w') as f:
json.dump(data, f)
#bot.command(pass_context=True)
async def reactionadd(ctx, emoji, *role:str):
role = ''.join(role)
with open("reactionroles.json", 'r') as f:
data = json.load(f)
message_id = data[str(ctx.guild.id)][1]['message-id']
message_id = int(message_id)
message = await ctx.channel.fetch_message(message_id)
await message.add_reaction(emoji)
role = discord.utils.get(ctx.guild.roles, name=role)
data[str(ctx.guild.id)][3]['emojis'].append(emoji)
print(role)
data[str(ctx.guild.id)][2]['roles'].append(str(role))
with open("reactionroles.json", 'w') as f:
json.dump(data, f, indent=4)
So the command reactionrole creates the embed, and writes some placeholder data into a json file. Afterwards, the reactionadd command adds the emoji unicode to a json array, and the role to a different json array. When on a reaction add, in on_raw_reaction_add(payload), payload only has the name of the emoji, and not the unicode. Because of this, I', not able to compare the two to see what role goes to what emoji. I can't save the origional, in reactionadd because I would run into problems in on_reaction_add. I'm lost on getting the unicode from the payload this is my final reach out. Here's what's inside payload:
<RawReactionActionEvent message_id=759903170721087508 user_id=146348630926819328 channel_id=754904403710050375 guild_id=665787149513261057 emoji=<PartialEmoji animated=False name='�😋' id=Non
event_type='REACTION_ADD' member=<Member id=146348630926819328 name='Chai' discriminator='6396' bot=False nick=None guild=<Guild id=665787149513261057 name="ChaiBot's Playground" shard_id=None chunked=True member_count=34>>>
From an Emoji object you can get the unicode character from emoji.name, or if you are looking for the unicode name you can use the python unicodedata library:
import unicodedata
unicodedata.name(emoji.name)
I have realized my error! I was able to compare the unicode from reactionadd to payload.emoji the entire time! I was not able to see originally though, that vs code shows the unicode as an emoji (in terminal), and not as the string. That makes much more sense now! Thanks to all they helped!

How to remove bot pagination response in discord.py

So I am using disputils and I've made a pagination embed. however, after it gets inactive the reactions get auto removed by the bot. I want to make the bot remove the whole embed but I've tried a lot of things such as using delete_after=(float) and even asyncio but it doesn't seem to be working.
#commands.group(aliases = ['ra'])
async def red(self, ctx):
if ctx.invoked_subcommand is None:
default = discord.Embed(title="`test`",color=discord.Colour.dark_red())
default.set_image(url="foo")
default.set_footer(text="Image by| user")
v1 = discord.Embed(title="example", description='test', color=discord.Colour.dark_red())
v1.set_footer(text="Info taken from| website")
v2 = discord.Embed(title="spam", description="foo" ,color=discord.Colour.dark_red())
v2.set_footer(text="Info taken from| website")
embeds = [
default,
v1,
v2,
]
paginator = BotEmbedPaginator(ctx, embeds)
await paginator.run()
I tried using delete_after(float) inside the paranthesis of await paginator.run() doesn't work. tried using it asycnio format and got an error Instance of 'BotEmbedPaginator' has no 'delete' member. Any help would be appreciated.
Just use DiscordUtils
Here is an example:
#commands.command()
async def paginate(self, ctx):
embed1 = discord.Embed(color=ctx.author.color).add_field(name="Example", value="Page 1")
embed2 = discord.Embed(color=ctx.author.color).add_field(name="Example", value="Page 2")
embed3 = discord.Embed(color=ctx.author.color).add_field(name="Example", value="Page 3")
paginator = DiscordUtils.Pagination.CustomEmbedPaginator(ctx, remove_reactions=True)
paginator.add_reaction('⏮️', "first")
paginator.add_reaction('⏪', "back")
paginator.add_reaction('🔐', "lock")
paginator.add_reaction('⏩', "next")
paginator.add_reaction('⏭️', "last")
embeds = [embed1, embed2, embed3]
await paginator.run(embeds)

Categories

Resources