Discord.py trouble with move_member() - python

Im having trouble with using move_member() for a python bot. The purpose of the command is to "kick" a user by moving them to a channel, then deleting it so that they disconnect from the voice call, but do not need an invite back to the server. I am aware that just moving a user accomplishes this purpose, but I would like for a user to disconnect instead.
import discord
import random
import time
import asyncio
from discord.ext import commands
from discord.ext.commands import Bot
bot = commands.Bot(command_prefix="!")
#bot.event
async def on_ready():
await bot.change_presence(game=discord.Game(name='with fire'))
print("Logged in as " + bot.user.name)
print(discord.Server.name)
#bot.command(pass_context=True)
async def kick(ctx,victim):
await bot.create_channel(message.server, "kick", type=discord.ChannelType.voice)
await bot.move_member(victim,"kick")
await bot.delete_channel("bad boi")
bot.run('TOKEN_ID')
the line gives the error:
The channel provided must be a voice channel
await bot.move_member(victim,"kick")
and this line gives this error:
'str' object has no attribute 'id'
await bot.delete_channel("kick")
Im pretty sure you have to get the channel id instead of "kick", but I don't see exactly how to do so, because the code below isnt working, even when I replace
ChannelType.voice to discord.ChannelType.voice
discord.utils.get(server.channels, name='kick', type=ChannelType.voice)

delete_channel('kick') will not work because you need to pass in a channel object and not a string.
You do not need to use discord.utils to get the channel you want. The create_channel returns a channel object, so you should be able to use that.
But, you do need to get the Member object that you're going to kick. You also made the mistake of referencing message.server rather than ctx.message.server
#bot.command(pass_context=True)
async def kick(ctx, victim):
victim_member = discord.utils.get(ctx.message.server.members, name=victim)
kick_channel = await bot.create_channel(ctx.message.server, "kick", type=discord.ChannelType.voice)
await bot.move_member(victim_member, kick_channel)
await bot.delete_channel(kick_channel)
Now if you're using rewrite library, you would have to do the following
#bot.command()
async def kick(ctx, victim):
victim_member = discord.utils.get(ctx.guild.members, name=victim)
kick_channel = await ctx.guild.create_voice_channel("kick")
await victim_member.move_to(kick_channel, reason="bad boi lul")
await kick_channel.delete()
As abccd mentioned in the comments, this is evaluated as a string, which will not guarantee the fact that you'll be kicking the right person. discord.utils.get will grab the first result, and not necessarily the correct user if multiple users have the same name.
A better approach would be to use #user or to use UserIDs. Here's an example in the old library
#bot.command(pass_context=True)
async def kick(ctx):
victim = ctx.message.mentions[0]
kick_channel = await bot.create_channel(ctx.message.server, "kick", type=discord.ChannelType.voice)
await bot.move_member(victim,kick_channel)
await bot.delete_channel(kick_channel)
I would highly recommend to start using the rewrite library since it's much more Pythonic and it's going to be the new library in the future anyways.

According to the Discord documentation, the call to delete_channel expects a parameter of type Channel.
For more information on the Channel class, refer to the Channel documentation
If I understand what you're attempting to do, for your code to run as expected, you would need to maintain a reference to the channel you are using as your temporary channel, and then change your offending line to:
await bot.delete_channel(tmp_channel)

Related

How to send message to a specific discord channel

I am trying to send a message to a specific channel and I can run the code below just nothing show up on the channel and I have no idea why... I put the channel Id in the get_channel input, just putting a random number here.
import discord
client = discord.Client()
async def send_msg(msg):
channel = client.get_channel(123456456788)
await channel.send('hello')
Is the function even called somewhere? Otherwise there could also be an issue with the discord permissions or the Intents.
This is one of many ways to call the function and post 'hello' in some specific channel. No msg parameter is required.
#client.event
async def on_ready():
await send_msg()
async def send_msg():
channel = client.get_channel(123456456788)
await channel.send('hello')

Discord.py failing to send message to a specific channel in a cog/extension file

I just recently started using cogs/extension files for Discord.py and ran into some issue that I don't know how to fix. I'm trying to send a message in a specific channel but I always just get the error AttributeError: 'NoneType' object has no attribute 'send'. I know that I can send a message in a specific channel with:
#client.command()
async def test(ctx):
await ctx.send("test")
channel = client.get_channel(1234567890)
await channel.send("test2")
And this works perfectly fine in my "main file", but not in my "extension file", so it's not because of a wrong ID. The await ctx.send("test") works without problems as well, together with any other command I have, just the channel.send is causing troubles.
I'm importing the exact same libraries & co and otherwise should have the exact same "setup" in both files as well.
NoneType error means that it doesn't correctly recognize the channel. When you use get_channel you are looking for the channel in the bot's cache which might not have it. You could use fetch_channel instead - which is an API call.
#client.command()
async def test(ctx):
await ctx.send("test")
channel = await client.fetch_channel(1234567890)
await channel.send("test2")
As you know, the error occurs because your channel is not recognized. The solution is fetch_channel(channel_id). The problem lies in your channel = client.get_channel (1234567890).
Try adding await before client. Next replace get_channel with fetch_channel.
For general use consider your get_channel(), instead you need fetch_channel (channel_id) to retrieve an x.GuildChannel or x.PrivateChannel with the specified ID.
#client.command()
async def test(ctx):
await ctx.send("test")
channel = await client.fetch_channel(1234567890) #update
await channel.send("test2")

Is there a way to kick members without using client = discord.Client() instead of a bot on Python

So, I'm new to programming and I have a discord bot, I used client = discord.Client() instead of using client = commands.Bot(...), and now i want to be able to kick users. But I can't see any command using my client to kick someone using their username.I konw it's simpler to do it with a bot but i have already such a big code that I don't want to redo it.
Help would be appreciated :)
If you change it to commands.Bot everything is going to work just fine (if you add await client.process_commands(message) at the end of the on_message event. But nevertheless here's how to make a kick 'command' using the on_message event:
#client.event
async def on_message(message):
guild = message.guild
if message.startswith('!kick'):
args = message.content.split()[1:]
member_id = int(args[0])
member = guild.get_member(member_id)
reason = ' '.join(args[1:])
await member.kick(reason=reason)
# If you actually change your mind and want to use `commands.Bot`
await client.process_commands(message)
# To invoke
# !kick 172399871237987 drama seeker
I strongly DO NOT recommend using this method at all, just compare how much better, easier and cleaner is with commands
#client.command()
#commands.has_permissions(kick_members=True)
async def kick(ctx, member: discord.Member, *, reason):
await member.kick(reason=reason)
# While invoking here you can actually mention the user
# !kick #some_user drama seeker
# But you also can use the ID
# !kick 761876328716327186 drama seeker
It's only 4 lines, 3 if we don't count the has_permissions decorator.

discord.py bot isn't answering when mentioned from phone app

I made recently a discord bot for small server with friends. It is designed to answer when mentioned, depending on user asking. But the problem is, when someone mention bot from a phone app, bot is just not responding. What could be the problem?
Code:
import discord
from discord.ext import commands
from discord.ext.commands import Bot
import asyncio
bot = commands.Bot(command_prefix = '=')
reaction = "🤡"
#bot.event
async def on_ready():
print('Bot is ready.')
#bot.listen()
async def on_message(message):
if str(message.author) in ["USER#ID"]:
await message.add_reaction(emoji=reaction)
#bot.listen()
async def on_message(message):
mention = f'<#!{BOT-DEV-ID}>'
if mention in message.content:
if str(message.author) in ["user1#id"]:
await message.channel.send("Answer1")
else:
await message.channel.send("Answer2")
bot.run("TOKEN")
One thing to keep in mind is that if you have multiple functions with the same name, it will only ever call on the last one. In your case, you have two on_message functions. The use of listeners is right, you just need to tell it what to listen for, and call the function something else. As your code is now, it would never add "🤡" since that function is defined first and overwritten when bot reaches the 2nd on_message function.
The message object contains a lot of information that we can use. Link to docs
message.mentions gives a list of all users that have been mentioned in the message.
#bot.listen("on_message") # Call the function something else, but make it listen to "on_message" events
async def function1(message):
reaction = "🤡"
if str(message.author.id) in ["user_id"]:
await message.add_reaction(emoji=reaction)
#bot.listen("on_message")
async def function2(message):
if bot.user in message.mentions: # Checks if bot is in list of mentioned users
if str(message.author.id) in ["user_id"]: # message.author != message.author.id
await message.channel.send("Answer1")
else:
await message.channel.send("Answer2")
If you don't want the bot to react if multiple users are mentioned, you can add this first:
if len(message.mentions)==1:
A good tip during debugging is to use print() So that you can see in the terminal what your bot is actually working with.
if you print(message.author) you will see username#discriminator, not user_id

Attribute Error: 'Client' object has no attribute 'command'

from discord.ext import commands
client = commands.Bot(command_prefix='{')
#client.command()
async def ping(ctx):
await ctx.send("Pong!")
I'm extremely new to Python and I'm currently learning how to program a discord bot with discord.py rewrite. I followed this code from a YouTuber named Lucas. This is his exact code. His seems to work but for some reason, my PyCharm still says that client has no attribute command. May someone teach me how to fix it?
This is the error
Traceback (most recent call last):
File "C:/Users/danie/PycharmProjects/Discord Tutorial/bot.py", line 93, in <module>
#client.command()
AttributeError: 'Client' object has no attribute 'command'
With my knowledge, if you wish to continue using the client part of discord.py, then you should try the on_message part of it, An example:
async def on_message(message):
if message.content.startswith('{ping'):
await message.channel.send('pong')
But if you want a reletivly easier alternative, (At least it makes more sense to me) You could try #bot.command Example:
import discord
from discord.ext import commands
TOKEN = ''
bot = commands.Bot(command_prefix='{')
#bot.command()
async def ping(ctx):
await ctx.send('pong')
One great thing about #bot.command is its easier to get input.
If you want to get what the user says after they do the command, then you could do.
#bot.command()
async def ping(ctx, *, variableName):
await ctx.send(f'You said {variableName}')
And if you want an error message if they mess up you could do
#bot.command()
async def ping(ctx, *, variableName):
await ctx.send(f'You said {variableName}')
#ping.error
async def ping_error(ctx, error):
ctx.send("Please enter something after the command")
And in my experience, it is much easier to find help on stackoverflow if you are using #bot.command as most other people use it as well. However, back to you wanting to use #client.command I do not know about that. However, if you want to switch over to #bot.command then I'm sure you can look up what you want to do on either google or stackoverflow and look until you find one for #bot.command Which shouldn't be that long.

Categories