Hello i'm making a Discord bot in Python. I'm making a meme command that gets a random submission from a subreddit. Well there is a little problem with it. When the submission is a video or an unavailble format for Discord, embed can't load the content. So i need to check for submissions format and when it's an unavailble format then the function should be recalled or something like that. I couldn't figure out myself so im asking for help. Here is the code:
#client.command()
async def meme(ctx):
if not hasattr(client, 'nextMeme'):
client.nextMeme = await getMeme()
title, url, img_url, upvotes, comments = client.nextMeme
embedVar = discord.Embed(title=title, url=url, color=discord.Color.random())
embedVar.set_image(url=img_url)
embedVar.set_footer(text=f"👍 {upvotes} | 💬 {comments}")
await ctx.send(embed=embedVar)
client.nextMeme = await getMeme()
async def getMeme():
meme_subreddits = ['dankmemes', 'memes', 'jaharia', 'videoyun']
subreddit = await reddit.subreddit(random.choice(meme_subreddits))
all_subs = []
top = subreddit.top(limit = 52)
async for submission in top:
all_subs.append(submission)
random_sub = random.choice(all_subs)
img_url = random_sub.url
title = random_sub.title
url = random_sub.shortlink
upvotes = random_sub.score
comments = random_sub.num_comments
return title, url, img_url, upvotes, comments
You could check if the image url you're getting ends with a supported file extension, with something like this:
if img_url.endswith(('.jpg', '.png', '.gif', '.jpeg')):
If you wanna try until you get a valid one, just put it in a while loop, something like this should work? I cant test it right now, sorry
img_url = ''
while not img_url.endswith(('.jpg', '.png', '.gif', '.jpeg')):
title, url, img_url, upvotes, comments = client.nextMeme
#rest of your code
You can obviously add more file extensions, these were just the ones I could come up with quickly. Hope this helps you at least a little bit
Related
I'm making test bot using aiogram now and i faced a problem.
I want to edit message media, but i only have a link to an image, and when i try to use an 'edit_media' method aiogram tells me that it can't parse JSON object.
(error)
In documentation said that 'media' parameter must be 'A JSON-serialized object for a new media content of the message'.
Here is my code:
code
#dp.callback_query_handler(kb.item_nav_cb.filter(action='next'))
async def item_next_cb_handler(query: types.CallbackQuery, callback_data: dict):
await bot.answer_callback_query(query.id)
logging.info(callback_data)
current_index = int(callback_data['index'])
current_index += 1
link = df_new['link'].iloc[current_index]
item_info = get_item_info.get_item_info(domen+link)
if link in favourites[f'user_{query.from_user.id}']:
item_kb = kb.get_item_fav_kb(index=current_index,
link=link)
else:
item_kb = kb.get_item_notfav_kb(index=current_index,
link=link)
await query.message.edit_caption(caption=f'<b>{item_info[0]}</b>\n{item_info[1]}\n\nЦена: {item_info[2]}',
reply_markup=item_kb)
await query.message.edit_media(media=item_info[3]) # Here is the problem
Found a solution. Needed to use InputMediaPhoto type:
photo = types.input_media.InputMediaPhoto(item_info[3])
await query.message.edit_media(media=photo)
And all together code looks like this:
#dp.callback_query_handler(kb.item_nav_cb.filter(action='next'))
async def item_next_cb_handler(query: types.CallbackQuery, callback_data: dict):
await bot.answer_callback_query(query.id)
logging.info(callback_data)
current_index = int(callback_data['index'])
current_index += 1
link = df_new['link'].iloc[current_index]
item_info = get_item_info.get_item_info(domen+link)
if link in favourites[f'user_{query.from_user.id}']:
item_kb = kb.get_item_fav_kb(index=current_index,
link=link)
else:
item_kb = kb.get_item_notfav_kb(index=current_index,
link=link)
photo = types.input_media.InputMediaPhoto(item_info[3]) # Makes a difference
await query.message.edit_media(media=photo)
await query.message.edit_caption(caption=f'<b>{item_info[0]}</b>\n{item_info[1]}\n\nЦена: {item_info[2]}',
reply_markup=item_kb)
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(",")
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)
Here's what it looks like on the desktop app: https://imgur.com/a/iDTrHsy
and here's what it looks like on mobile (Android): https://imgur.com/a/RV3tvZJ
Here's my code:
#client.command()
async def draw(ctx):
group_of_items = [
'[***Seiyaryu***](link)',
'[Crawling Dragon #2](link)']
num_to_select = 2
list_of_random_items = random.sample(group_of_items, num_to_select)
first_random_item = list_of_random_items[0]
second_random_item = list_of_random_items[1]
embed = discord.Embed(
description = f'You drew: {first_random_item}\nand\n{second_random_item}',
colour = discord.Colour.from_rgb(47,128,49)
)
embed.set_footer(text="Bot of Greed", icon_url="link")
await ctx.send(embed=embed)
Any way to fix this so it shows the text formatting on mobile also?
There is nothing you can do, and it's been an issue for years now.
I don't have much hope for Discord fixing it.
I am creating a discord bot for me and my friends and would like to be able to have the bot save an image URL as a command. Then whenever that command is called it will recall the saved image URL displaying that image. Basically, if we find a meme or funny picture we want to be able to recall it using a name we can remember.
Example:
$save dog (image url to dog pic)
Image saved as $dog
$dog
Bot Posts: (image url to dog pic)
I am somewhat new to python and I thought making this bot would be a fun way to learn.
I have already tried some code to save the URL and it works, but I am not sure where it saves it. I also need to be able to remove any links that do not work, or if I want to replace an already named image URL. I am using the discord.py rewrite version.
Thank you for any help you can provide!
#bot.command(name='save')
async def save_url(ctx, name, *, link):
await ctx.send('Saved as: $' + name)
#bot.command(name=name)
async def send_url(img):
await img.send(name)
await img.send(link)
#bot.command(name=remove)
async def get_rid(ctx, rid):
if rid == name:
name = None
await ctx.send("Imaged removed")
elif rid != name:
await ctx.send("Image could not be found.")
EDIT:
I think I have found a solution thanks to #Patrick Haugh I added the image URLs to a json file and saved them that way as well as changed the way the imaged is called.
Instead of $(image URL name) its now $img (image URL name)
Here is the code for any other discord.py people, please let me know if I can make it better, or have any critiques!
def write_json(title, img):
with open('urls.json') as jfile:
urldict = json.load(jfile)
urldict[title] = img
with open('urls.json', 'w') as jfile:
json.dump(urldict, jfile, sort_keys=True, indent=4)
def delete_json(delete):
try:
with open('urls.json') as jfile:
data = json.loads(jfile.read())
del data[delete]
with open('urls.json', 'w') as f:
json.dump(data, f, sort_keys=True)
y = 'Image' + delete + 'is removed.'
return y
except KeyError:
e = 'Image ' + delete + ' not found!'
return e
def read_json(title):
try:
with open('urls.json') as jfile:
get_url = json.load(jfile)
pic = get_url[title]
return pic
except KeyError:
e = 'Image ' + title + ' not found!'
return e
def read_json_names():
with open('urls.json') as jfile:
get_url = json.load(jfile)
pic = str(get_url.keys())
if pic == 'dict_keys([])':
return 'No images saved!'
else:
pic = pic.lstrip('dict_keys([')
pic = pic.rstrip('])')
return pic
## bot commands ##########################################
#bot.command(name='save')
async def save_url(ctx, name, *, link):
write_json(name, link)
await ctx.send('Saved as: $' + name)
#bot.command(name='remove')
async def remove_url(ctx, thing):
k = delete_json(thing)
await ctx.send(k)
#bot.command(name='img')
async def call_url(ctx, call):
p = read_json(call)
await ctx.send(p)
#bot.command(name='listimg')
async def call_all_urls(ctx):
m = read_json_names()
await ctx.send(m)