How would I detect user activities? | discord.py - python

I'm trying to make a bot that when a command is entered it detects a users activities. I wrote some code, but the response from the bot I get is not what I wanted. That's my code:
from discord import Member
from discord.ext import commands
bot = commands.Bot(command_prefix='!')
#bot.command()
async def status(ctx):
await ctx.send(Member.activities)
bot.run('token')
And this is what I get in response:
<member 'activities' of 'Member' objects>
How can I fix this? Would anyone help me?

It seems you are new to python. Python is an object oriented programming language, means that you need to make the difference between a class and an instance.
In your case, you are fetching the class attribute, though you want the instance attribute.
What you wanted to do:
#bot.command
async def status(ctx):
await ctx.send(ctx.author.activities)
Though, that would send a python-formatted list, so that's still not what you want.
What I guess you want to do:
#bot.command
async def status(ctx):
await ctx.send(ctx.author.activities[0].name)
Please note, you need more code as this command like that would raise an error if the member doesn't have any activity.

Related

How do you make it so there is an introduction embed in discord.py?

For example:
Let's say that this is the intro embed for every new bot user:
Let's say that there are commands like BEG, HELP, WORK and all these many commands that this bot supports... But if you are a new bot user and you type '(prefix) beg' you WON'T beg, instead, you will get this embed shown above because you are new. And after that you can use the bot normally...
How would you do this?
Can you use something along the lines of:
#client.event
async def on_new_user():
await ctx.send(embed=introduction_embed)
Or is there a different way? How do I ensure that every user saw this intro embed before anything and make sure that they only see it ONCE? I am working on a discord bot using python. Would appreciate some help! Thanks so much
Something like this:
on_command is run when a command is found, if I decorate it with before_invoke I can raise an error after sending the embed, preventing the command from running the first time for each user. It's up to you how to store the users though.
The CommandError is caught and passed into on_command_error event.
registered_users = []
#bot.before_invoke
#bot.event
async def on_command(ctx):
global registered_users
if ctx.author not in registered_users:
registered_users.append(ctx.author)
embed = discord.Embed(
color=discord.Colour.random(),
title="WELCOME",
description="welcome message",
)
await ctx.send(embed=embed)
raise commands.CommandError("Error")

Python, going through a list and calculating how much values are in there

currently having this error:
#tasks.loop(seconds=5)
async def adMessageSend():
channel = client.get_channel(786258218925293629)
await channel.send(adMessage)
AttributeError: 'NoneType' object has no attribute 'send'
The bot has access to the channel, and this function only runs when the bot is ready, so im unsure why it cannot find this channel?
You have to define the intents. If you look at the API References, you can see that in order to use client.get_channel(), you have to define it.
from discord.ext import commands
import discord
intents = discord.Intents().all()
client = commands.Bot(command_prefix='', intents=intents)
#tasks.loop(seconds=5)
async def adMessageSend():
channel = client.get_channel(786258218925293629)
await channel.send(adMessage)
if you indent your last two lines, it should work just fine for you so long as your variables are defined

How can you call a function in discord.py

I am new to discord.py and I am stuck on this error. I am trying to call the command removerole later in the code.
This first part works fine, I can type in discord chat:
.removerole admin Rythm
And it works, but I get an error in the second part:
'str' object has no attribute 'remove_roles'
import discord
from discord.ext import commands
client = commands.Bot(command_prefix = '.')
#client.command()
async def removerole(ctx, role: discord.Role, member: discord.Member):
await member.remove_roles(role)
await ctx.send(f'Successfully removed {role.mention} from {member.mention}')
I want to type .removeRythm in chat and the bot would remove the admin role from Rythm.
#client.command()
async def removeRythm():
await removerole(".remove", "admin", "Rythm")
Does anybody know how to do this if it even is possible to do?
Thanks MB
You are passing into the removerole method 3 strings. ".remove", "admin", "Rythm". "Rythm" is not a discord object but a String. Annotations in Python have no meaning and the compiler totally ignores them. So highlighting that member is of type discord.Member does not actaully change anything, but only confuses you.
Instead you should pass in a discord user object into the method.
I changed like so and it now works
#client.command()
async def removeRythm():
await removerole(ctx, ctx.message.guild.get_role(779716603448787004), ctx.message.guild.get_member(235088799074484224))
Thanks for the help.

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.

Discord.py trouble with move_member()

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)

Categories