Pagination - Discord.py rewrite - discord.py

I've been trying to make a command that will display some information and then, when i react to an emote, its supposed to display another set of information.
I tried to use parts of this, specifically the parts in line 335 to 393
to get it to work. However, it just does nothing. Not even an error message.
This is the code I use right now.
def check_react(reaction, user):
if reaction.message.id != msg.id:
return False
if user != ctx.message.author:
return False
return True
res, user = await bot.wait_for('reaction_add', check=check_react, timeout=None,)
if user != ctx.message.author:
print('if user != ctx.message.author:')
elif '⬅️' in str(res.emoji):
page -=1
print(page)
embed = discord.Embed(title='generic title', description='generic description', color=0x52fffc)
await msg.edit(embed=embed)
elif '➡️' in str(res.emoji):
page +=1
print(page)
embed = discord.Embed(title='generic title 2', description='generic description 2', color=0x52fffc)
await msg.edit(embed=embed)
It seems to stop at
await bot.wait_for('reaction_add', ..)
why is that? and how can i make the code work? Thats in a cog btw. I'll happily provide more code if needed.

Better and easier way is to 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)

Forgot about this, and i figured it out eventually. Here's how i did it:
At first i put all the content of the pages in a list. Each entry is a page.
Then i define a function that will act as a check. This one will restrict the reaction listener to the actual embed that was sent and prevents anyone from reaction other than the command invoker. Sorry for any Formatting Errors.
def check(reaction, user):
return reaction.message.id == msg.id and user == ctx.author #msg.id is the id of the embed sent by the bot.
page = 0
while True: #can be changed to a variable to let it work a certain amount of times.
try:
reaction, _ = await bot.wait_for('reaction_add', timeout= 20.0, check=check)
if reaction.emoji == 'emote of choice here' and page > 0:
page -= 1
embed = discord.Embed(title='Title Here', description=pages[page]
await msg.edit(embed=embed)
if reaction.emoji == 'emote of choice here' and page < len(pages) -1:
page += 1
embed = discord.Embed(title='Title Here', description= pages[page]
await msg.edit(embed=embed)
except asyncio.TimeoutError:
#do stuff here, could be pass or a message saying the timeout has been reached or something similar.

Related

Discord.py Check doesnt seem to apply. Doesnt do anything

I wanted to create a bot with a spam feature, but with the condition that it checks for a stop message every cycle. I have tried looking at other posts but neither of them really helped or worked. The check doesn't seem to do aynthing as if the code doesn't reach it. I tried to spot any of the "checked" messages I put into the code to be displayed in the console, but they are not printed, thus my suspicion.
I get no errors in the console, and typing ' $stop ' does nothing. Any Idea why?
Thank you.
async def bot_spam(message):
try:
msg = message.content.split(' ')
if msg[2] == '1':
await message.channel.send(f"You will ping {msg[1]}, once.")
elif msg[2] == '0':
await message.channel.send("You cant ping 0 times.")
return
else:
await message.channel.send(f"You will ping {msg[1]}, {msg[2]} times.")
time.sleep(1)
msgr = int(msg[2])
global spam
spam = True
while spam is True and msgr > 0:
def check1(msg1: discord.Message):
print("checked")
if msg1.content == "$stop":
return False
return True
try:
if await bot.wait_for('message', check=check1, timeout=1.5):
print("checked 2")
await message.channel.send("Stopping.")
spam = False
except asyncio.TimeoutError:
await message.channel.send(f"{msg[1]}")
msgr -= 1
await message.channel.send("Done.")
except IndexError:
await message.channel.send("Your arguments don't make sense \n It's '$spam #someguy timesyouwantpinged'")
This is a logic issue
def check1(msg1: discord.Message):
print("checked")
if msg1.content == "$stop":
return False
return True
You are returning False when "$stop" is typed, thus the bot keeps waiting for a message until check returns True
Created a variable that checks for $stop using on_message outside the cycle instead of within it.
async def on_message(message):
if message.author == client.user:
return
else:
if message.content == "$stop":
stop = True
return
...
while stop is False and msgr > 0:
await message.channel.send(f"{msg[1]}")
time.sleep(0.5)
msgr -= 1
if stop is True:
await message.channel.send("Stopped.")
else:
await message.channel.send("Done.")

Having trouble with check = True using on_raw_reaction_add

I'm having trouble with my check = True. I can't seem to get identify the member making the reaction. Here is the code:
#bot.command()
async def buy(ctx):
reaction = await ctx.reply('Pick \U0001f44d')
#bot.event
async def on_raw_reaction_add(payload: discord.RawReactionActionEvent):
def check(pl):
return pl == payload.member and str(payload.emoji) == '\U0001f44d'
try:
pl = await bot.wait_for('raw_reaction_add', timeout=3.0, check=check)
except asyncio.TimeoutError:
await channel.send("no one picked")
await payload.member.send("you")
else:
if payload.emoji == '\U0001f44d':
await channel.send("you picked 1")```
My I idea is to have someone call the command and then allowing more than one member to be able to react thus the bot.event. What am I doing wrong for my check to not = True?
Maybe you have an issue with the check
I suggest to replace your check with this:
check = lambda payload: payload.message_id == msg.id and payload.channel_id == ctx.channel.id and str(payload.emoji) == '\U0001f44d'
payload = await client.wait_for('raw_reaction_add', check=check, timeout=30)

Discord.py create an embed message command

I was trying to make a embed command with time limit, só i started doing it, and at my first try to make it timed it didn't work.
So i searched here, found one sample and tried to do like it (as you can see at my code below), but it didn't work too.
Then i tried to copy that code and pasted at my bot.
Guess...it didn't work -_-, now i'm here, asking gods to help.
client.command(aliases=["createEmbed", "embedCreate"])
async def embed(ctx,):
Questions = ["Titulo?", "Cor? (Hex sem #)", "Descrição?"]
Responses = []
def check(m):
return m.author == ctx.author and m.channel == ctx.channel
#try:
await ctx.send(Questions[0])
title = await client.wait_for('message',timeout=2.0,check=check)
#except asyncio.TimeoutError(*title):
#await ctx.send("Demorou muito")
#return
#else:
Responses.append(title.content)
await ctx.send(Questions[1])
cor = await client.wait_for('message',timeout=25.0,check=check)
Responses.append(cor.content)
await ctx.send(Questions[2])
descrição = await client.wait_for('message',timeout=25.0,check=check)
Responses.append(descrição.content)
cor2 = Responses[1]
corHex = int(cor2, 16)
embedVar = discord.Embed(title=Responses[0], description=Responses[2], color=corHex)
await ctx.send(embed=embedVar)
At my code you can see the piece with #, that is the piece that i tried to test the time command.
If i remove the time command, it works.
It is better to loop through questions and get the date after that make the embed. Below is an example of how to get the Title and Description. You can modify it how you like
#client.command(aliases=["createEmbed", "embedCreate"])
async def embed(ctx):
questions = ["Title?", "Description?"]
responses = []
def check(m):
return m.author == ctx.author and m.channel == ctx.channel
for question in questions:
try:
await ctx.send(question)
message = await client.wait_for('message', timeout=15, check=check)
except asyncio.TimeoutError:
await ctx.send("Timeout")
return
else:
responses.append(message.content)
embedVar = discord.Embed(title=responses[0], description=responses[1])
await ctx.send(embed=embedVar)

Discord.py How to DM a user from the user ID in a cog even if the user is not in the server I run the command?

I am working on a command that removes a bug, then rewards the user with a bug report token (bugreport)
then dm's them.
So how do I get a User ID even if that user is not in the server that I run this command in?
the code I have for getting and dming the user:
//user is gotten from a query, it is a real ID
userobj = ctx.guild.get_user(user)
dm = await userobj.create_dm()
msg = 'msg'
dm.send(msg)
#commands.command(name='fixbug', allises=['finishbug'],help='[Owner Only] <bugid> <reward?>')
#commands.is_owner()
async def killbug(self, ctx, bugid: int, reward: str = 'False', msg: str = None):
print(bugid)
query = await db.load(
f'''
SELECT * FROM buglogs
WHERE fixedid = {bugid}
''')
print(query)
query = query[0]
await db.query(
f'''
DELETE FROM buglogs
WHERE fixedid = {bugid}
''')
user = query[1]
name = query[3]
log = query[2]
userobj = ctx.guild.get_user(user)
dm = await userobj.create_dm()
if reward == 'True' or reward == 'true' or reward == 'yes':
await self.add_item(user, 'bugreport', 1)
await ctx.send(f'Gave {name} A Bug Report Token, I also squashed \"{log}\" bug!')
await dm.send(f"Thank you for reporting the bug: \"{log}, You have been rewarded 1 Bug Report Token, sell it for your reward!")
else:
await ctx.send('Squashed: {log}')
if msg == None:
dm.send('The bug you reported ({log}) has been resolved, thank you!')
else:
dm.send(msg)
You can use bot.get_user
discordUser = self.bot.get_user(user) #pass user id here
if discordUser is not None:
#do stuff
else:
await ctx.send('user not found')
Warning: this code assumes you are in a cog and have set self.bot = bot in the init like in the docs
References:
get_user

Discord.py Rewrite Custom Help Embed Sort commands by Cog

Ok so I'm working on one of my older bots and am attempting to rewrite my custom help command to be a bit less manual. However, I'm not sure how to get this working as intended.
My issues are as follows:
It keeps responding with the I can't send embeds exception
There's no error showing up in the console logs
Can anyone help me figure this out?
Here is my custom Help command.
#commands.command(name="help", aliases=["Help", "H", "h"])
#commands.has_permissions(add_reactions=True, embed_links=True)
async def help(self, ctx, *cog):
"""Gets all cogs and commands.
Alt : h, H, Help
Usage : [h]elp <cog or command>"""
try:
if not cog:
"""Cog listing. What more?"""
embed = discord.Embed(color=discord.Color.dark_gold(),
title='Cog Listing and Uncatergorized Commands',
description=f'Use `{prefix}help <cog>` to find out more about them!\nNote: The Cog Name Must Be in Title Case, Just Like this Sentence.',
timestamp=ctx.message.created_at)
embed.set_author(name=self.client.user.name, icon_url=self.client.user.avatar_url)
cogs_desc = ''
for x in self.client.cogs:
cogs_desc += ('{} - {}'.format(x, self.client.cogs[x].__doc__) + '\n')
embed.add_field(name='Cogs', value=cogs_desc[0:len(cogs_desc) - 1], inline=False)
cmds_desc = ''
for y in self.client.walk_commands():
if not y.cog_name and not y.hidden:
cmds_desc += ('{} - {}'.format(y.name, y.help) + '\n')
embed.add_field(name='Uncatergorized Commands', value=cmds_desc[0:len(cmds_desc) - 1], inline=False)
await ctx.send('', embed=embed)
else:
"""Helps me remind you if you pass too many args."""
if len(cog) > 1:
embed = discord.Embed(color=discord.Color.dark_red(), timestamp=ctx.message.created_at)
embed.set_author(name="Command Failed", icon_url=self.client.user.avatar_url)
embed.add_field(name="Error", value="Too many cogs", inline=False)
await ctx.send('', embed=embed)
else:
"""Command listing within a cog."""
found = False
for x in self.client.cogs:
for y in cog:
if x == y:
embed = discord.Embed(color=discord.Color.dark_gold(), timestamp=ctx.message.created_at, title=cog[0] + ' Command Listing', description=self.client.cogs[cog[0]].__doc__)
for c in self.client.get_cog(y).get_commands():
if not c.hidden:
embed.add_field(name=c.name, value=c.help, inline=False)
found = True
if not found:
"""Reminds you if that cog doesn't exist."""
embed = discord.Embed(color=discord.Color.dark_red(), timestamp=ctx.message.created_at)
embed.set_author(name="Command Failed", icon_url=self.client.user.avatar_url)
embed.add_field(name="Error", value='Can not use "' + cog[0] + '"?', inline=False)
else:
await ctx.send('', embed=embed)
except:
await ctx.send("I can't send embeds.")
I'm using discord.py-rewrite if it helps.
---EDIT---
I gave up on the above code due to countless issues with it. And went for the following code. I'd still like it to be less manual but for now this one actually posts.
#commands.command(name="Help", aliases=["help", "h", "H"])
async def _help(self, ctx):
"""Displays all available commands"""
msg = ctx.message
await msg.delete()
contents = [
f"```css\nAdministrator Commands\n\nBroadcast: [B]roadcast <message>\nPurge: [p]urge <1-100>\nBan: [B]an <user> [reason]\nUnban: [U]nban <user>\nKick: [K]ick <user> [reason]\n\nOptional arguments are represented with []\nRequired arguments are represented with <>\nDo not include the [] or <> flags in the command\n ```",
f"```css\nModerator Commands!\n\nAnnounce: [ann]ounce <message>\nClean: [C]lean <1-100>\n\nOptional arguments are represented with []\nRequired arguments are represented with <>\nDo not include the [] or <> flags in the command\n ```",
f"```css\nFun Commands\n\nGiphy: [ ] < >\nTenor: [ ] < >\n\nOptional arguments are represented with []\nRequired arguments are represented with <>\nDo not include the [] or <> flags in the command\n ```",
f"```css\nUtility Commands\n\nPing: ping\nJoined: [J]oined [user]\nTopRole: [top]role [user]\nPerms: perms [user]\nHelp: [H]elp [command]\n\nOptional arguments are represented with []\nRequired arguments are represented with <>\nDo not include the [] or <> flags in the command\n ```"
]
pages = 4
cur_page = 1
message = await ctx.send(f"Page {cur_page}/{pages}:\n{contents[cur_page-1]}")
# getting the message object for editing and reacting
await message.add_reaction("◀️")
await message.add_reaction("▶️")
def check(reaction, user):
return user == ctx.author and str(reaction.emoji) in ["◀️", "▶️"]
# This makes sure nobody except the command sender can interact with the "menu"
while True:
try:
reaction, user = await self.client.wait_for("reaction_add", timeout=60, check=check)
# waiting for a reaction to be added - times out after x seconds, 60 in this
# example
if str(reaction.emoji) == "▶️" and cur_page != pages:
cur_page += 1
await message.edit(content=f"Page {cur_page}/{pages}:\n{contents[cur_page-1]}")
await message.remove_reaction(reaction, user)
elif str(reaction.emoji) == "◀️" and cur_page > 1:
cur_page -= 1
await message.edit(content=f"Page {cur_page}/{pages}:\n{contents[cur_page-1]}")
await message.remove_reaction(reaction, user)
else:
await message.remove_reaction(reaction, user)
# removes reactions if the user tries to go forward on the last page or
# backwards on the first page
except asyncio.TimeoutError:
await message.delete()
break
# ending the loop if user doesn't react after x seconds
#_help.error
async def _help_error(self, ctx, error):
if isinstance(error, commands.MissingRequiredArgument):
guild = ctx.guild
embed = discord.Embed(
color=discord.Color.dark_red(), timestamp=ctx.message.created_at)
embed.set_author(name="Command Failed",
icon_url=self.client.user.avatar_url)
embed.add_field(name="Missing Required arguments",
value="Please pass in all required arguments.", inline=False)
embed.set_thumbnail(url=self.client.user.avatar_url)
embed.set_footer(text=f"{guild.name}", icon_url=guild.icon_url)
await ctx.message.add_reaction(emoji="⚠️️")
await ctx.message.author.send(embed=embed)
print("[ERROR] Missing Required Arguments")
elif isinstance(error, commands.MissingPermissions):
guild = ctx.guild
embed = discord.Embed(
color=discord.Color.dark_red(), timestamp=ctx.message.created_at)
embed.set_author(name="Access denied",
icon_url=self.client.user.avatar_url)
embed.add_field(name="Insufficient Permissions",
value="You do not have permission to use this command.", inline=False)
embed.set_thumbnail(url=self.client.user.avatar_url)
embed.set_footer(text=f"{guild.name}", icon_url=guild.icon_url)
await ctx.message.add_reaction(emoji="🚫")
await ctx.message.author.send(embed=embed)
print("[ERROR] Insufficient Permissions")
But yes, if anyone knows how to make it so the commands are read from the cogs instead of manually typed into the help command's response any tips would be very helpful.

Resources