Nextcord button bot error tab error inconsistent use of tabs and spaces in indentation - nextcord

My code
#bot.command(name='support')
async def support(ctx):
hi = Button(label="click me", style=ButtonStyle.blurple)
subscribe = Button(label="subscribe", url="https://www.youtube.com/channel?sub_confirmation=1")
async def hi_callback(interaction):
hi = client.get_user(id)
await hi.send("hello")
hi.callback = hi_callback
myview = View(timeout=180)
myview.add_item(hi)
myview.add_item(subscribe)
await ctx.send("hi", view=myview)
My error
File main.py, line 27
hi = client.get_user(id)
tab error inconsistent use of tabs and spaces in indentation

So in order for you to make your command to work you are going to have to create a class that way you can call the URL to the Button.
Also since you are using a link you cannot use style=ButtonStyle.blurple you must use style=ButtonStyle.link
Your command should look something like this:
class SupportButton(View):
def __init__(self):
super().__init__()
self.add_item(Button(style=ButtonStyle.link, url='https://www.youtube.com/channel?sub_confirmation=1', label="Click me!"))
self.value = None
#bot.command(name='support')
async def support(ctx):
view = SupportButton()
await view.wait()
if view is None:
return
elif view.value is True: #Debugging
await ctx.send("nothing")
else:
await ctx.send('Sorry there was a issue when processing your request')

Related

How can I edit an embed field with a button in Discord.py?

Basically, I'm making a poll command. I want it to put the user's vote in the embed field, and obviously make it so they can't vote again, again, and again. No idea how to do this.
Command Preview Here
Here's the code:
class Buttons(discord.ui.View):
def __init__(self, *, timeout = 180):
super().__init__(timeout=timeout)
#discord.ui.button(label="Yes", style=discord.ButtonStyle.success, emoji='👍')
async def upvote_button(self, button : discord.ui.Button, interaction : discord.Interaction):
pass
#discord.ui.button(label="No", style=discord.ButtonStyle.danger, emoji='👎')
async def downvote_button(self, button : discord.ui.Button, interaction : discord.Interaction):
pass
class Poll(commands.Cog):
def __init__(self, bot):
self.bot = bot
#app_commands.command(name="poll", description="Ask a question and receive upvotes or downvotes (Yes/No)")
async def poll(self, interaction : discord.Interaction, *, question : str):
embed = discord.Embed(
description=question,
color = 0xb037e1
)
embed.set_author(name="Poll", icon_url=self.bot.user.avatar)
embed.set_footer(text="Asked by: " + str(interaction.user), icon_url=interaction.user.avatar)
embed.add_field(name="Upvotes", value="X", inline=True)
embed.add_field(name="Downvotes", value="X", inline=True)
await interaction.response.send_message(embed=embed, view=Buttons())
Probably very simple, although I still haven't thought about a way
The easiest way to do this is by using dictionaries, lists, or even sets to store the users that have clicked.
For this example, I will use one list to store the users who have clicked the upvote and downvote buttons. Like here:
class Buttons(discord.ui.View):
def __init__(self, *, timeout=None):
super().__init__(timeout=timeout or 180)
self.voted_users = []
self.upvote_count = 0
self.downvote_count = 0
#discord.ui.button(
label="Yes", style=discord.ButtonStyle.success, emoji="👍"
)
async def upvote_button(
self, interaction: discord.Interaction, button: discord.ui.Button
):
if (
interaction.user in self.voted_users
): # check if the user has already voted or not and return if true
return await interaction.response.send_message(
content="You've already voted!", ephemeral=True
)
self.upvote_count += 1
self.voted_users.append(interaction.user) # add the user to voted list
await interaction.response.send_message("Upvoted!", ephemeral=True)
#discord.ui.button(label="No", style=discord.ButtonStyle.danger, emoji="👎")
async def downvote_button(
self, interaction: discord.Interaction, button: discord.ui.Button
):
if (
interaction.user in self.voted_users
): # check if the user has already voted or not and return if true
return await interaction.response.send_message(
content="You've already voted!", ephemeral=True
)
self.downvote_count += 1
self.voted_users.append(interaction.user) # add the user to voted list
await interaction.response.send_message("Downvoted!", ephemeral=True)
By the way, interaction always comes before the button in the button callback argument if you're using discord.py.

Discord sniping edited messages not working

I've scrolled through other people's posts about this, ive tried reworking their code to mine, but it doesnt seem to work
snipe_message_author = {}
#client.event
async def on_message_edit(message_before, message_after):
snipe_message_author = message_before.author
guild = message_before.guild.name
#client.command()
async def snipeedit(ctx):
channel = ctx.channel
try:
snipeEmbed = discord.Embed(colour = discord.Colour.orange(),title=f"{snipe_message_author[channel.id]}", description = f"""Original message : {message_before.content}
Updated message : {message_after.content}""")
await ctx.send(embed = snipeEmbed)
except:
await ctx.send(f"There are no edited messages in #{channel.name}")
Every time i try the code, it returns "There are no edited messages in #*channel*"
I think its because of the snipe_message_author
thanks to anyone who helps.
As Łukasz Kwieciński's comment says:
You never add anything to snipe_message_author = {}, it can't work at all. Based on other posts, you can easily come up with a solution.
Take a look at the following code:
edited_messages = {}
#client.event
async def on_message_edit(message_before, message_after):
edited_messages[message_before.guild.id] = (message_before.content, message_after.content, message_before.author)
#client.command()
async def snipeedit(ctx):
try:
content_before, content_after, message_author = edited_messages[ctx.guild.id]
snipeEmbed = discord.Embed(color=discord.Colour.orange(), title=f"{message_author}",
description=f"Original message : {content_before}
Updated message : {content_after}")
await ctx.send(embed=snipeEmbed)
except:
await ctx.send(f"There are no edited messages in #{ctx.channel.name}")
In our on_message_edit event, we first define what should be "saved" for our guild or what exactly applies.
After we define these things, they are saved in the order specified. So now we have 3 "data" stored. We query or redefine these in our try statement and then read them from edited_messages for the corresponding ctx.guild.

Giphy API not responding in discord.py

I made a discord bot that shows you gifs when you type a certain command but the problem is that it works fine in the first half but takes a long time to show the gifs when not used.
Basically it doesn't show the gifs instantly when not used.
Here's the code that I've written:
#client.command()
async def gif(ctx, *, q = 'dance'):
api_key = 'Some Key here'
api_instanc = giphy_client.DefaultApi()
try:
api_responce = api_instanc.gifs_search_get(api_key, q, limit = 7,rating = 'r')
lst = list(api_responce.data)
giff = random.choice(lst)
emb = discord.Embed(title = f"Requested by {ctx.author} " + q )
emb.set_image(url= f'https://media.giphy.com/media/{giff.id}/giphy.gif')
await ctx.channel.send(embed = emb)
except ApiException as e:
await ctx.channel.send("API EXCEPTION")
It doesn't show any errors but doesn't work after the long time.
Any re-write of the code with aiohttp will be appreciated because I am learning that.
I think the module you are using is not asynchronous which leads to blocking read more.
Default in the command is search = None you can use that with an if statement to check.
After that is the request for the api to get the image.
Here is the code edited to use aiohttp
# import aiohttp
# import random
#bot.command()
async def giphy(ctx, search: str = None):
api_key = ""
embed = discord.Embed(title=f"Requested by {ctx.author}")
async with aiohttp.ClientSession() as session:
# search
if search:
embed.description = search
async with session.get(f'http://api.giphy.com/v1/gifs/search?q={search}&api_key={api_key}&limit=10') as response:
data = await response.json()
gif_choice = random.randint(0, 9)
embed.set_image(url=data['data'][gif_choice]['images']['original']['url'])
# radnom
else:
async with session.get(f'http://api.giphy.com/v1/gifs/random?api_key={api_key}&limit=10') as response:
data = await response.json()
embed.set_image(url=data['data']['images']['original']['url'])
await ctx.send(embed=embed)

News command discord.py

I've made a news command in discord.py using newsapi, I'm having a problem where it sends the top 10 headlines one by one, I wanna make it so that it sends the headline in one embed.
Here's the code :
#commands.command()
async def news(self, ctx):
open_bbc_page = requests.get(main_url).json()
article = open_bbc_page["articles"]
results = []
for ar in article:
results.append(ar["title"])
for i in range(len(results)):
ree = (i + 1, results[i])
em = discord.Embed(title="Here's the trending news", description = f"{ree}",color = 0xa3a3ff)
await ctx.send(embed=em)[enter image description here][1]
[1]: https://i.stack.imgur.com/Fel1n.jpg
You could put them all into the description of the embed like this:
for ar in article:
results.append(ar["title"])
embeddescription = '/n'.join(results)
em = discord.Embed(title="Here's the trending news", description = embeddescription,color = 0xa3a3ff)
await ctx.send(embed=em)
Just need to make sure they arent longer than 2048 characters combined, this is the limit for embed descriptions.
def set_news(ctx, content)
with open('news.json', 'r') as f:
msg = json.load(f)
msg[str("news")] = content
with open('news.json', 'r') as f:
json.dump(msg, f)
def check_news()
with open('news.json', 'r') as f:
msg = json.load(f)
return msg
#bot.command()
async def news_set(ctx, content):
set_news(ctx, content)
await ctx.send("I set news to {content}!")
#bot.command()
async def news(ctx):
news = check_news()
await ctx.send(f"News: {news}")

Pagination - Discord.py rewrite

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.

Resources