is there another command should i use? - discord.py

So, I can't use the "?roast" command and "?roast #(user)" at the same time...
#client.event
async def on_ready():
await client.change_presence(status=discord.Status.dnd, activity=discord.Game(' "?" Booe'))
print('Bot is ready to play!')
#client.command()
async def roast(ctx, member:discord.Member):
roast_messages = [
f'{ctx.message.author.mention}You are useless as the UEUE in Queue {member.mention}',
]
await ctx.send(random.choice(roast_messages))

There is always a way to solve that , discord gives us a way like this
#client.command()
async def roast(ctx, member:discord.Member=None):#None is if nothing is given then its None
if member == None:
member = ctx.author
roast_messages = [
f'{ctx.message.author.mention}You are useless as the UEUE in Queue {member.mention}',]
await ctx.send("imagine roasting yourself")#Your Choice Absolutely :)
await ctx.send(random.choice(roast_messages))
here if the member isnt specified , the function is called taking member as none , later gives the none value to the ctx.author itself (dont try to write ctx.author instead of none in the async def roast it gives error as ctx aint defined. also i forgot your roast messages wont make sense then so make sure to edit them too TY :)

Related

Command raised an exception: AttributeError: 'str' object has no attribute 'send'

I'm trying to do a custom embed command and i got this error.
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'str' object has no attribute 'send'
And this is my code:
#client.command()
#commands.has_permissions(administrator=True)
async def embed(self, ctx,*, msg=None):
if msg == None:
await ctx.send("No Message has been provided. Please write your message within 30secs.")
def check(message):
return message.author == ctx.author and message.channel == ctx.channel
try:
mes=await self.client.wait_for('message',check=check,timeout=30.0)
except asyncio.TimeoutError:
await ctx.send('Timeout! Please be quicker next time.')
else:
msg=mes.content
em=discord.Embed(
description=msg,
timestamp=datetime.utcnow(),
color=discord.Color.random()).set_author(
name=f'{ctx.author.name}#{ctx.author.discriminator}',
icon_url=f'{ctx.author.avatar_url}')
await ctx.send(embed=em)
If u can patch it please say me below :(
You're doing
#client.command()
#commands.has_permissions(administrator=True)
async def embed(self, ctx,*, msg=None):
If you're in a cog, you need to be doing #commands.command. When doing client.command decorator though, you're adding the callback itself (and it isn't called from the class). The actual context is passed to self, and ctx becomes your first argument (a string) while the other argument msg just stays as None.
If you are in a cog, then change it to a normal command.
#commands.command()
#commands.has_permissions(administrator=True)
async def embed(self, ctx,*, msg=None):
#testy.command(name='d')
#commands.has_permissions(administrator=True)
async def embed(ctx, msg=None):
if msg == None:
await ctx.send("No Message has been provided. Please write your message within 30secs.")
def check(message):
return message.author == ctx.author and message.channel == ctx.channel
try:
mes=await testy.wait_for('message',check=check,timeout=30.0)
except asyncio.TimeoutError:
await ctx.send('Timeout! Please be quicker next time.')
else:
msg=mes.content
em=discord.Embed(description=msg, timestamp=datetime.datetime.utcnow(), color=discord.Color.random())
em.set_author(name=ctx.author, icon_url=ctx.author.avatar)
await ctx.send(embed=em)
Using your code as a base, I tweaked a couple of things and verified it worked on my tester bot. You can see the name of my bot is "testy" so you'll want to replace that with your client.
The command is invoked with the command 'd' and then prompts the user for a text string. That string is then displayed in an embed with a timestamp and the user's discord name and avatar.
Hope this leads you in the right direction.
I am not sure what you are passing in for ctx, but it looks like you're passing in a string for ctx based off of the error, in which case there is no send() function for a string object

I want to make a command that deletes a channel discord.py

Here is what I got so far
It is saying that "await" is outside of async function and I am just confused on how to fix this. I copied part of the code from a giveaway command because that is my only source of Q&A code I have
#commands.has_permissions(administrator = True)
async def cdelete(ctx):
embed=discord.Embed(title = Which channel would you like to delete?)
await ctx.send(embed=embed)
answer = []
def check(m):
return m.author == cx.author and m.channel == ctx.channel
try:
await client.wait_for('message', timeout=15, check=check)
except asyncio.TimeoutError:
await ctx.send("Timeout. Please run the command again")
else:
answer.append(message.content)
try:
c_id= int(answer[0][2:-1])
await ctx.channel.delete
await ctx.send("Channel Deleted")
except:
await ctx.send("Thats not a valid channel!")```
If you just want a command you can make it a lot easier if you just execute a command with the channel name. You can have a look at the following:
#client.command()
#commands.has_permissions(administrator=True)
async def cdelete(ctx, channel_name):
"""Deletes a channel by name or ID."""
channel_id = int(''.join(i for i in channel_name if i.isdigit())) # Get channel ID
existing_channel = client.get_channel(channel_id) # Get channel ID with defined method
if existing_channel: # If channel with the name/ID exists
await existing_channel.delete()
else: # If the channel does not exist
await ctx.send(f'**No channel named `{channel_name}` was found.**')
We have a method to catch the channel ID and also pass that in as a valid argument. If the ID or channel name then exists we delete the channel.
You can here either mention the channel or pass in the ID.
Usage would be: cdelete #channel/ID.
If you want to avoid a long console output if you input no channel/ID/name you can build in an error handler:
#cdelete.error
async def cdelete_error(ctx, error):
if isinstance(error, commands.MissingRequiredArgument):
await ctx.send("You need to name a channel.")
The problem you have here is with the check() function. According to the doc you only can use await inside of an async function. To solve the problem change def check(m): into async def check(m):

How do I take in user input in discord.py

This may be kinda dumb but I'm trying to make a purge command but theres always something wrong with it. Can anyone help please?
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('p!purge'):
numberoftimes = input(int('How many times: '))
await message.channel.purge(limit=str(numberoftimes))
I'll start with answering your question, then I'll clarify on a better way to create a purge command. To answer your question, there is no need to make an input() statement. Rather, this is how you make an input prompt with a Discord bot:
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('p!purge'):
await message.channel.send('How many messages do you want to purge?')
while True:
numberoftimes = client.wait_for('message') # This means, the client is waiting for a message
if numberoftimes.author == message.author: # Make sure that the person responding is the person who did the command
limit = int(numberoftimes.content) # If its a string, it will be treated as a word. You want to purge a "number" of messages
await message.channel.purge(limit=limit+1)
That's how you would purge messages in a channel. But, the way you are creating this command can be made simpler. You can use the command decorator, which is the "standard" way of doing things:
import discord
from discord.ext import commands
client = commands.Bot(command_prefix='p!')
#client.command()
#commands.has_permissions(manage_messages=True)
async def purge(ctx, limit):
limit = int(limit)
await ctx.channel.purge(limit=limit + 1)

get channel name and send a message over at that channel

So I am working on a little project here, and pretty much, I want to have one of those "Please type the name of a channel in this server" feature.
So pretty much, the bot asks for a channel name, and I put in for example "#changelog" - and then it will ask for what it should write in that channel, etc etc.
So need to get the channel id (I am guessing), but I don't want users to write the ID, instead only writing the #server-name. And then whenever I have done that, the bot shall write in that channel.
Here is my current code!
class Changelog(commands.Cog):
def __init__(self, client):
self.client = client
#commands.Cog.listener()
async def on_ready(self):
print('Changelog is loaded')
#commands.command()
async def clhook(self, ctx):
await ctx.send('Write text-channel: ')
text_channel = await self.client.wait_for("message", check=lambda message: message.author == ctx.author, timeout=300)
clhook = self.client.get_channel(text_channel)
def setup(client):
client.add_cog(Changelog(client))
Edit:
The channel ID shall be saved "forever", meaning that I do not have to re-write the channel name where the message should go!
You can use discord.utils.get() with this example:
text_channel = await self.client.wait_for("message", check=lambda message: message.author == ctx.author, timeout=300)
channel = discord.utils.get(ctx.guild.text_channels, name=text_channel)
await channel.send('Bla Bla')
So when you type (prefix)clhook then only the channel name, for example general, it will send Bla Bla to the channel named general .
There is another way to do this and I think it's simple than the first option, here it is:
#commands.command()
async def clhook(self, ctx, channel: discord.TextChannel):
await channel.send('Bla Bla')
So in this command, usage is changed. You can use that with this: (prefix)clhook #general(mention the channel). I suggest this solution and I think it's more useful.
You can use message.channel_mentions. This will return a list of all channels that were mentioned using the #channel-name notation. That way, you can just use channel.id to get the id of the channel they mentioned.
Don't forget, however, to check if the user did in fact tag a channel (which you can also put in your check). I put it in a separate function to make it a bit more readable for the sake of this reply, but you can fit that in your lambda if you really want to.
Also, make sure to check if it's a Text Channel and not a Voice Channel or Category Channel.
#commands.command()
async def clhook(self, ctx):
def check(self, message):
author_ok = message.author == ctx.author # Sent by the same author
mentioned_channel = len(message.channel_mentions) == 1 and isinstance(message.channel_mentions[0], discord.TextChannel)
return author_ok and mentioned_channel
await ctx.send("Write text-channel: ")
text_channel = await self.client.wait_for("message", check=check)
chlhook = text_channel.channel_mentions[0]
I put two conditions on the mentioned_channel line, because if the first one fails, the second one could cause an IndexError. Alternatively you can also use an if-statement to return sooner at that place to solve the same issue.

This Ban command does not work... How can I fix it?

Here is my ban command! Everytime I want to ban someone it dosen't go thru else! To be honest it dosen't do anything other than the if! Please help!
#bot.command() #ban (verified works)
#commands.has_permissions(ban_members = True)
async def ban(ctx, member : discord.Member, *, reason = None):
if member == ctx.author or member.id == bot.user.id:
await ctx.send("Unfortunatly I cannot do that!")
return
else:
await ctx.send('Banned the member {}'.format(ctx.member.mention))
await member.ban(reason = reason)
await ctx.message.delete()
I recommend not using the role to check if the user can use the command, rather try using something like this:
#client.command()
#commands.has_permissions(ban_members=True)
async def ban(ctx, member : discord.Member,*,reason=None):
try:
await member.ban(reason=reason)
embed = discord.Embed(description=f":white_check_mark: succesfully banned {member.mention}!",color=0x00ced1)
await ctx.send(embed=embed)
except:
e2 = discord.Embed(description="You don't have permission to use this command",color=0xff0000)
await ctx.send(embed=e2)
This allows you to use the bot in multiple servers, who don't necessarily have the same roles, and also narrows it down to a certain permission.

Resources