Discord.py Uploading Random Images - python

Not sure if its the lack of coffee, but I'm having a slight issue with uploading random images.
#client.command(aliases=['cuddle'])
async def _cuddle(ctx, *, user):
image= [
'file_1.gif',
'file_2.gif',
'file_3.gif',
'file_4.gif',
'file_5.gif',
'file_6.gif',
'file_7.gif']
await ctx.send(f'You got a Cuddle from{ctx.message.author.mention}, {user}!\n {random.choice(file =discord.file(image))}')
its mostly the
{random.choice(file =discord.file(image))}
ive tryed
discord.file'file_1.gif', method but with no prevail.

I've solved it for anyone who wants to know
import os
#commands.command(aliases=['image'])
async def images(self, ctx):
image = os.listdir('./cogs/image/')
imgString = random.choice(image) # Selects a random element from the list
path = "./cogs/image/" + imgString
await ctx.send(file=discord.File(path))

Related

How to edit images in embeds (discord.py)

I have a command that generates a random color palette and it works pretty well. Then I wanted to add a button to it, a button that'd generate a new palette. I added the button, wrote a callback, but the callback just won't work, because the interaction.response.edit_messsage() shows an error:
TypeError: edit_message() got an unexpected keyword argument 'file'
I know what that means, I cannot have a file=file line there, but if I don't no image is sent in the embed... Embeds just need that to work properly (assuming that you're generating an image from scratch, it's simpler if you provide a link).
I have no clue what I could do to get the desired functionality now. Previously I'd create images, send them in a secret channel, get those images' links and use them in the embed. It worked then, but it was painfully slow.
Here's the code that I currently have:
#bot.tree.command(name="palette", description="Generates a random color palette")
async def palette(interaction: discord.Interaction):
async def get_color_palette():
try:
response = requests.post("http://colormind.io/api/", json={"model": "default"}).json()
colors = response["result"]
colors = [tuple(x) for x in colors]
except requests.exceptions.RequestException as e:
return None, f"An error occurred while getting the color palette: {e}"
return colors, None
async def create_image(colors):
# create an image with a black background
wide = 300
tall = int(wide / 5)
image = Image.new("RGB", (wide, tall), (0, 0, 0))
draw = ImageDraw.Draw(image)
# draw squares with those colors
x, y = 0, 0
width, height = wide / 5, tall
for color in colors:
draw.rectangle((x, y, x + width, y + height), fill=color)
x += width
# save the image
image_data = BytesIO()
image.save(image_data, "PNG")
image_data.seek(0)
return image_data
colors, error = await get_color_palette()
if error:
return await interaction.response.send_message(embed=discord.Embed(description=error))
image = await create_image(colors)
file = discord.File(image, "color_palette.png")
embed = discord.Embed()
embed.set_author(
name="Here's your random color palette:",
icon_url="https://media.discordapp.net/attachments/1060711805028155453/1061825040716402731/logo_beter.png")
embed.set_image(
url="attachment://color_palette.png")
embed.set_footer(
text="Generated with colormind.io")
button = discord.ui.Button(label="Generate again", style=discord.ButtonStyle.gray)
view = View()
view.add_item(button)
async def button_callback(interaction):
colors, error = await get_color_palette()
if error:
return await interaction.response.send_message(embed=discord.Embed(description=error))
image = await create_image(colors)
file = discord.File(image, "color_palette.png")
embed = discord.Embed()
embed.set_author(
name="Here's your random color palette:",
icon_url="https://media.discordapp.net/attachments/1060711805028155453/1061825040716402731/logo_beter.png")
embed.set_image(
url="attachment://color_palette.png")
embed.set_footer(
text="Generated with colormind.io")
await interaction.response.edit_message(file=file, embed=embed, view=view)
button.callback = button_callback
await interaction.response.send_message(file=file, embed=embed, view=view)
How can I achieve that? Any tips for the future?
That first comment is not true; you can attach the image you wanted to edit with the attachments argument of the edit_message method.
For example, this simple command sends an embed with an image named img1.png and has a button that, if you click it, will edit the embed and set the new image to img2.png.
#bot.command()
async def send(ctx: commands.Context):
simple_view = ui.View()
simple_button = ui.Button(label="Change Image")
async def simple_callback(button_inter: Interaction):
new_file = File("img2.png")
new_embed = Embed(title="Button clicked")
new_embed.set_image(url="attachment://img2.png") # set the embed's image to `img2.png`
await button_inter.response.edit_message(embed=new_embed, attachments=[new_file]) # attach the new image file with the embed
simple_button.callback = simple_callback
simple_view.add_item(simple_button)
file = File("img1.png")
embed = Embed()
embed.set_image(url="attachment://img1.png")
await ctx.send(embed=embed, file=file, view=simple_view)
And here's the example response:

Problem creating a discord bot for rolling dice

This is my first trying creating a discord bot. I want it to work like this:
User:
/roll 2d20+4
Then my bot will roll 2d20, save the sum and the bigger. Finally, it will print like this:
Output:
Bigger: 16+4=20 | Sum: 23+4=27.
This is the code I have:
import hikari
import lightbulb
import random
disc_token="..."
server_id="..."
bot=lightbulb.BotApp(
token=disc_token,
default_enabled_guilds=int(server_id)
)
#bot.command
#lightbulb.command('roll',"Role dados (exemplo: 2d20+5)")
#lightbulb.implements(lightbulb.SlashCommand)
async def roll(ctx,play):
die_split=play.split("d")
final_split=die_split[1].split("+")
n_die=int(die_split[0])
die=int(final_split[0])
extra=int(final_split[1])
play=[n_die,die,extra]
best_roll=0
sum_roll=0
for i in range(n_die):
actual_roll=random.randint(1,die)
sum_roll=sum_roll+actual_roll
if(actual_roll>best_roll):
best_roll=actual_roll
sum_roll=sum_roll+extra
extra_roll=best_roll+extra
play_print='Bigger: '+str(best_roll)+'+'+str(extra)+'='+str(extra_roll)+' | Sum: '+str(sum_roll)
await ctx.respond(play_print)
bot.run()
What is happening:
The bot is working (I tested some basic commands, like "Hello World" and works fine), but when I try to run the /roll command, for the discord user it shows:
"! The app did not answered".
At my terminal, the error was displayed like this:
Traceback (most recent call last):
File "C:\Users\MateusRochaQSOFT\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\lightbulb\app.py", line 1163, in invoke_application_command
await context.invoke()
File "C:\Users\MateusRochaQSOFT\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\lightbulb\context\base.py", line 328, in invoke
await self.command.invoke(self)
File "C:\Users\MateusRochaQSOFT\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\ligh raise new_exc
lightbulb.errors.CommandInvocationError: An error occurred during command 'roll' invocation
What could be wrong?
I think you're defining your options wrong for using the lightbulb package. You have to define the options using the #lightbulb.option decorator and can then access them via ctx.options. Where the name of the option is the property you can get.
#bot.command
#lightbulb.option("play", "dice roll")
#lightbulb.command('roll',"Role dados (exemplo: 2d20+5)")
#lightbulb.implements(lightbulb.SlashCommand)
async def roll(ctx):
play = ctx.options.play
die_split = play.split("d")
final_split = die_split[1].split("+")
n_die = int(die_split[0])
die = int(final_split[0])
extra = int(final_split[1])
play = [n_die,die,extra]
best_roll = 0
sum_roll = 0
for i in range(n_die):
actual_roll = random.randint(1, die)
sum_roll = sum_roll + actual_roll
if actual_roll > best_roll:
best_roll = actual_roll
sum_roll = sum_roll + extra
extra_roll = best_roll + extra
play_print = f"Bigger: {best_roll} + {extra} = {extra_roll} | Sum: {sum_roll}"
await ctx.respond(play_print)
bot.run()
Found in the documentation here. You can access the play variable using ctx.options.play.
I've also formatted the code to use PEP8 formatting and I used f-strings in place of the string concatenation that you were doing.
You can also use the pass_options parameter in #lightbulb.command to pass all the defined options (via decorators) as keyword arguments.
Like this:
#bot.command
#lightbulb.option("play", "dice roll")
#lightbulb.command('roll',"Role dados (exemplo: 2d20+5)", pass_options=True)
#lightbulb.implements(lightbulb.SlashCommand)
async def roll(ctx, play):
This way you don't need to do play = ctx.options.play.

"This interaction failed" : discord.py Button

so currently I try to program a calculator but I hit a roadblock. Well, I watched a tutorial by Glowstik on how to make calculator discord bot but it seems that his code doesn't work anymore. So, can anybody suggest changes that I can make to the code to make the bot work? Thanks in advance.
Here is the code :
import discord
import os
from discord.ext import commands, tasks
from online import keep_alive
from discord_slash import SlashCommand
from itertools import cycle
from discord_components import *
import datetime
client = commands.Bot(command_prefix="!")
slash = SlashCommand(client, sync_commands=True)
status = cycle([
" Unanswered Question of Life", " Self - Referential Paradox",
" Near-infinite density?", " Dark matter ?",
" Measurement of the speed of light in one straight line",
" Schrodinger's cat ???",
"The light side of Discord is the path of many unnatural abilities"
])
#client.event
async def on_ready():
print("I have logged in as {0.user}".format(client))
status_swap.start()
DiscordComponents(client)
buttons = [[
Button(style=ButtonStyle.grey, label='1'),
Button(style=ButtonStyle.grey, label='2'),
Button(style=ButtonStyle.grey, label='3'),
Button(style=ButtonStyle.blue, label='+'),
Button(style=ButtonStyle.red, label='Clear')
],
[
Button(style=ButtonStyle.grey, label='4'),
Button(style=ButtonStyle.grey, label='5'),
Button(style=ButtonStyle.grey, label='6'),
Button(style=ButtonStyle.blue, label='-'),
Button(style=ButtonStyle.red, label='Exit')
],
[
Button(style=ButtonStyle.grey, label='7'),
Button(style=ButtonStyle.grey, label='8'),
Button(style=ButtonStyle.grey, label='9'),
Button(style=ButtonStyle.blue, label='×'),
Button(style=ButtonStyle.red, label='←')
],
[
Button(style=ButtonStyle.grey, label='00'),
Button(style=ButtonStyle.grey, label='0'),
Button(style=ButtonStyle.grey, label='.'),
Button(style=ButtonStyle.blue, label='÷'),
Button(style=ButtonStyle.red, label='=')
]]
def calculator(exp):
o = exp.replace('×', '*')
o = o.replace('÷', '/')
result = " "
try:
result = str(eval(o))
except:
result = "An error occurs"
return result
#client.command()
async def operator(ctx):
m = await ctx.send(content="Loading calculator")
expression = "None"
delta = datetime.datetime.utcnow() + datetime.timedelta(minutes = 5)
e = discord.Embed(title="Basic Operation Calculator",description=expression)
await m.edit(components=buttons, embed=e)
while True :
res = await client.wait_for("button click")
while m.created_at < delta :
if res.author.id == int(res.message.embeds[0].title.split("|")[1]) and res.message.embeds[0].timestamp < delta:
expression = res.message.embeds[0].description
if expression == "None" or expression == 'An error occurs':
expression = ''
elif res.component.label == 'Exit':
await res.respond(content='Calculator Closed. Thanks for using Basic Operation Calculator.',type=7)
break
elif res.component.label == "←":
expression = expression[:-1]
elif res.component.label == 'Clear':
expression = None
elif res.component.label == '=':
expression += calculator(expression)
else:
expression = res.component.label
f = discord.Embed(title='Basic Operation Calculator',description=expression)
await res.respond(content='', embed = f, component=buttons, type=7)
# tasks.loop(minutes=5)
async def status_swap():
await client.change_presence(activity=discord.Game(next(status)))
keep_alive()
client.run(os.getenv('MATH_VAR'))
This code looks like it was taken from https://www.youtube.com/watch?v=3BGcgSm9sv0
which coincidentally I have also used.
Your problem arises from your embed title because it's based around your title having a '|' followed by the user's ID.
try changing the embed title from "Basic Operation Calculator" to f"{ctx.message.author}'s calculator|{ctx.message.author.id}" and tell me if that works. I've modified the code I'm using slightly, so this might be wrong, I'm going off of memory here. If that does work, also try f"Basic Operation Calculator|{ctx.message.author.id}" if you want to keep your title name.
This isn't needed but if you also want to add a sliver of text after the '|', you need to change the split statement in
if res.author.id == int(res.message.embeds[0].title.split("|")[1]) and res.message.embeds[0].timestamp < delta:
to the '|' and any text (thats not the ID) directly after.
so if I want to add "ID: " after, then the split statement would be "| ID: ". Sorry if this sounds confusing, the way this code works is very specific, and I'm pretty new to Stack Overflow. Let me know if you run into any errors or have any questions. If nothing else works I'm happy to send you my current code I'm using since It's only slightly modified. Next time you post a question, try your best to be as specific as possible with your question.

This Interaction Failed - Discord_components - Discord.py

Hello I recently made a help command using discord_components buttons (I know they arent fully supported by Discord.py) but I still went ahead. The problem is that whenever I run the command and receive the Buttons to click on, they alway say "This Interaction Failed". I can't seem to find what's wrong. Please help.
Thanking You,
NightMX.
import discord
from discord.ext import commands
from discord_components.component import ButtonStyle
from discord_components import DiscordComponents, Button, Select, SelectOption
from discord_components.interaction import InteractionType
class BotCommands(commands.Cog):
def __init__(self, client):
self.client = client
#commands.command()
async def helpv2(self, ctx):
funbutton = Button(style=ButtonStyle.grey, label="Fun Commands", id="funcmds")
monkedevbutton = Button(style=ButtonStyle.grey, label="Attachment Commands", id="monkecmds")
# utilitybutton = Button(style = ButtonStyle.grey, label = "3", id = "embed3")
funembed = discord.Embed(title="Fun Commands", colour=discord.Colour.orange())
funembed.add_field(name="k.joke", value="Sends a Random joke from PyJokes")
monkedevembed = discord.Embed(title="Fun Commands", colour=discord.Colour.blurple())
monkedevembed.add_field(name="k.dog", value="Sends a Random Dog Fact")
monkedevembed.add_field(name="k.monkey", value="Sends a Monkey's Picture")
monkedevembed.add_field(name="k.bird", value="Sends a Bird's Picture")
await ctx.send(
"Kola's Beta Help Command!",
components=[[funbutton, monkedevbutton]]
)
buttons = {
"funcmds": funembed,
"monkedcmds": monkedevembed
}
while True:
event = await self.bot.wait_for('button_click')
if event.channel is not ctx.channel:
return
if event.channel == ctx.channel:
response = buttons.get(event.component.id)
if response is None:
await event.channel.send(
"Something went Wrong"
)
if event.channel == ctx.channel:
await event.respond(
type=InteractionType.ChannelMessageWithSource, embed=response
)
def setup(client):
client.add_cog(BotCommands(client))
should be content="something" instead of embed = response

Run 2 Discord Bots in 1 Project (Discord.py)

I'm coding 10 discord bots for fun, all of these have the same code, (but different token) how can I run all bots with 1 code? Thank you.
import random
import time
import discord
from discord.ext import commands
messaggio = "ti sto dando fastidio?"
client = client = commands.Bot(command_prefix = "()")
Client = discord.Client()
#client.event
async def on_ready():
print("Sono online e pronto ad infastidire")
#client.command() #Invia messaggi in privato ad un utente taggato.
async def infastidisci(ctx, member : discord.Member, numero_di_messaggi = 1):
for x in range(numero_di_messaggi):
y = random.uniform(0.25, 1.50)
time.sleep(y)
print(f"Messaggio inviato a {member}. Messaggi restanti: ", numero_di_messaggi - x - 1)
await member.send(messaggio)
#client.command()
async def infastidisci_chat(ctx, numero_di_messaggi = 1):
for x in range(numero_di_messaggi):
messaggio_fastidioso = "#everyone vi sto dando fastidio?"
canali = ctx.message.guild.text_channels
y = random.uniform(0.25, 1.50)
time.sleep(y)
for canale in canali:
await canale.send(messaggio_fastidioso)
print(f"Messaggio inviato in {canale}. Messaggi restanti: {numero_di_messaggi - x -1}")
client.run(token)
One method:
You retrieve the token from an environment variable:
import os
token = os.environ.get("TOKEN", None)
You execute your program from command line with:
TOKEN=mytoken python3 main.py
What changed here is you have to define the environment variable TOKEN.
Now you can just execute the process multiple time. You can also wrap it in a single command line
TOKEN=mytoken1 python3 main.py & TOKEN=mytoken2 python3 main.py

Categories