I just wrote a discord bot and used a function to show me the members of each guild the bot is in. That worked all the time but now i wanted to use a other server so i copied my files and dragged them on the other server. But for some reason now it says the sum of all the member = 0. Can someone help me?
Thx in advance ^^
async def member():
while True:
for guild in my_guild_id: # list of guild id's
guild = bot.get_guild(guild)
member = sum(discord.member and not member.bot for member in guild.members)
for channel in members_channel_id: # list of channel id's
check = str(guild.get_channel(channel)).encode('ascii', 'ignore')
if check != none: # none = b'None' cause there were some bugs
channel = bot.get_channel(channel)
await channel.edit(name=f"đ„Servermember: {Member}")
await asyncio.sleep(20)
Your function has the same name as a variable in the function, you should be using a different name for it.
Also, none takes a capitalized N: None.
Finally, you're using the variable Member when editing the channel, but this variable isn't defined, python is case-sensitive.
I don't think you just "copied and dragged" your files, and that couldn't work on another server...
Related
I have made a bot which automates role adding and removal. It all works, but the adding works in 15/20 seconds after running the command. The removal takes up to 15 minutes.
What am I doing wrong? I have started a few months ago with programming and started with Python, so any hint is usefull.
The guildid, channelid and roleid are numbers now, I put placeholders in.
#tasks.loop(seconds=10)
async def autoderolergame():
tasks = []
guild = client.get_guild(guildid)
channel = guild.get_channel(channelid)
role = guild.get_role(roleid)
for member in guild.members:
if member not in channel.members:
try:
await member.remove_roles(role, reason='Leaving Voice channel')
except:
pass
if str(member.status) == 'offline':
try:
await member.remove_roles(role, reason='Going offline, so no more VIP rain')
except:
pass
I also try to subtitute 'for member in guild.members' with
'async for member in guild.fetch_members():'
Sadly this made no difference.
I am thinking about saving a list of users in the channel and updating that every 10 seconds and then look at the list and select all users which aren't in the channel anymore, remove the role and then remove them from the list, would that be a better solution?
I rather don't because I would like to use the built in functions of Discord.py.
Thanks for your help!
You can use an asynchronous approach to make it faster
import asyncio
remove_roles_semaphore = asyncio.Semaphore(20)
async def remove_role(member, role, reason):
async with remove_roles_semaphore:
try:
await member.remove_roles(role, reason=reason)
except:
pass
#tasks.loop(seconds=10)
async def autoderolergame():
guild = client.get_guild(guildid)
channel = guild.get_channel(channelid)
role = guild.get_role(roleid)
tasks = []
for member in guild.members:
if member not in channel.members:
tasks.append(remove_role(member, role, 'Leaving Voice channel')
if str(member.status) == 'offline':
tasks.append(remove_role(member, role, 'Going offline, so no more VIP rain')
await asyncio.gather(*tasks)
Though keep in mind that you can get easily ratelimited for this, if you hit the global ratelimit (50 requests per second) you can get banned. Use this method at your own risk (you might want to enable logging to see any ratelimit warnings)
I used asyncio.Semaphore to limit the amount of requests made concurrently, feel free to change the value, but remember -- the higher the value the higher the chances to get banned (do not exceed 50).
Sadly I cannot really test the code so I can't promise that it's going to be faster.
I found a way to solve the problem.
I was using the code to look at all the guild members.
Since I want roles to be removed upon leaving the channel, I only needed too look at the roles a user has and then check if they are still in the room.
So this is my new code:
#tasks.loop(seconds=10)
async def autoderolergame():
tasks = []
guild = client.get_guild(guildid)
channel = guild.get_channel(channelid)
role = guild.get_role(roleid)
for member in role.members: (<-- only changed this from guild to role)
if member not in channel.members:
try:
await member.remove_roles(role, reason='Leaving Voice channel')
except:
pass
if str(member.status) == 'offline':
try:
await member.remove_roles(role, reason='Going offline, so no more VIP rain')
except:
pass
I also changed to seconds to a longer interval because of the tip Ćukasz KwieciĆski gave me regarding the rate limit. It's not an issue now since it works like 1000x times faster.
I have tried reading the docs, but I don't understand what is going on here and how to fix it. I am trying to map a mention to its proper Name#NNNN form, but alas, it is proving to be a fruitless endeavor for me.
import discord
from discord.ext import commands
from collections import defaultdict
client = commands.Bot(command_prefix=">")
#client.event
async def on_ready():
print('Ready!')
jobz = {}
'''PART 1 v v v'''
#client.event
if message.content.startswith('>jobsched'):
author = message.author
jobz[author].append(...)
await channel.send(jobz[author])
'''PART 2 v v v'''
if message.content.startswith('>when '):
channel = message.channel
worker = list(filter(None, message.content[6:].split(' ')))[0]
uname = message.mentions[0].mention
await channel.send(jobz[uname])
PART 1:
I run this first, the send works as expected as seen below:
>jobsched 'a'
>jobsched 'b'
As seen in the last line, this spits out ['1a', '2b']
PART 2:
Here is where I have my issue.
>when #Name
I expected this to spit out ['1a', '2b'] because I expected it to look up or translate the mentioned name, find its respective name and discriminator. I thought this should happen since, in the above piece, that is how the name gets written into the dictionary is i.e. Name#1234: ['1a','2b']
Printing out .keys() shows that the key has the name and discriminator i.e. Name#1234 in the 'jobz' dictionary.
However, I can't seem to get the mention to give me the Name and Discriminator. I have tried doing mentions[0].mention from what I have seen here on stackoverflow, but it doesn't result in a Member class for me, just a string, presumably just '#Name'. If I leave it alone, as shown in my 'worker' variable, it passes an empty list. It should pull the list because when I override it to jobz['Name#1234'] it gives me the list I expect.
Can anyone please help?
just cast the member object to string to get the name and discriminator as it says in the discord.py docs. To mention someone, put the internal representation like this: f'<#{member.id}>'. To stop problems like this, use client.command() it's way easier to put in parameters, and easier to access info. So, here would be the code:
#client.command()
async def when(ctx, member: discord.Member):
await ctx.send(jobz[str(member)])
Also, if your worker variable is returning None, you're not passing a parameter at all
mentions is a list of Member objects, so when you do mentions[0] you are referencing a Member. Thus, mentions[0].mention is the formatted mention string for the first-mentioned (element 0) Member.
You probably want mentions[0].name and mentions[0].discriminator
See: https://discordpy.readthedocs.io/en/latest/api.html#discord.Message.mentions
I am trying to use a command to give a specific role using DiscordPy, but every search I use brings me to the same answers, that don't help: 1, 2, 3.
Clearly, I'm missing a fundamental part, but i have no idea what. The documentation, covers that there is a add_roles command, but that doesn't give any explanation of how to use it for another user. In fact, trying await add_roles("Team Captain") gives the error NameError: name 'add_roles' is not defined.
What am I missing here? Why does add_roles not exist when it's documented, and how do I use it against a different user.
This is (some of) what I have at the moment, but obviously, doesn't work:
import discord, discord.utils, random, os, re, json
from discord.ext import commands
from discord.utils import get
from dotenv import load_dotenv
client = discord.Client()
load_dotenv()
key = os.getenv('DISCORD_KEY')
#client.event
async def on_message(message):
if message.author == client.user:
return
print('Message from {0.author}: {0.content}'.format(message))
#Want these commands in the right channel
if str(message.channel).lower().startswith("bot"):
if message.content.lower().startswith("$addcaptain"):
if len(message.mentions) == 0:
await message.channel.send("Needs a user to give Team Captain role.")
return
else:
await add_roles("Team Captain") #Doesn't work, and I assume would be against the user who sent the message, not the mentioned one
client.run(key)
key = os.getenv('DISCORD_KEY')
add_roles is a method that belongs to the Member object. This means that you'll need to get the target member, in your case message.mentions[0] as message.mentions returns a list of Members, and then stick .add_roles(..) on the end of it.
Additionally, when adding a role, it accepts Role objects, not just a name or ID. This means you'll need to fetch the role first, which can be done in a multitude of ways, but the one I'll use is utils.get() (other methods such as Guild.get_role() are also available)
This brings us to your code:
#client.event
async def on_message(message):
# code
if str(message.channel).lower().startswith("bot"):
if message.content.lower().startswith("$addcaptain"):
if len(message.mentions) == 0:
await message.channel.send("Needs a user to give Team Captain role.")
return
else:
role = discord.utils.get(message.guild.roles, name="Team Captain")
await message.mentions[0].add_roles(role)
References:
utils.get()
Message.mentions - message.mentions[0] gets the first element of the list, which is the discord.Member that was mentioned.
Member.add_roles()
Guild.get_role() - If you want to use this, you'll do:
role = message.guild.get_role(112233445566778899)
where 112233445566778899 is the Team Captain's role ID.
So I have this script,
good_users=[]
async def callposts(ctx):
g0=str(ctx.guild)
g=g0.replace(' ','_')
sqluse(g)
x="SELECT authorid, COUNT(*) FROM posts GROUP BY authorid"
mycursor.execute(x)
k=mycursor.fetchall()
for user in k:
if user[1] > 7:
good_users.append(user)
k.remove(user)
print(user)
return k
async def kick(ctx, uid):
await ctx.guild.kick(ctx.guild.get_member(int(uid)))
#client.command(pass_context = True)
async def post_check(ctx):
ausers=list(ctx.guild.members)
lowposters= await callposts(ctx)
for user in ausers:
if user == client.user:
print(user.name+" is a bot!")
ausers.remove(user)
elif user.id in exempt:
print(user.name+" is exempt!")
ausers.remove(user)
elif user.id in good_users:
print(user.name+" is a good user!")
ausers.remove(user)
else:
await kick(ctx,user.id)
print(ausers)
What I am trying to do here is remove inactive users. So I have 2 lists that I want to compare the memberlist to, exempt and good_users. I also am checking to make sure it isn't the bot. So this script removes the bot from the list but it doesn't remove the user that's in exempt or good users. So in turn it tries to kick everyone that's not a bot. They are trying to take over!
I'm looking this over but right now I'm sick so not 100%.
The prints are just for troubleshooting purposes however, all but the firt print in the callpost function print nothing and that one for some reason only prints the user, now it isn't printing the bot so the bot may not be in the list to get removed.
Any thoughts?
You're never appending anything to exempt_users and because of the scope of good_users it is only filled with users within callposts() because you're not returning it when calling it in post_check().
Changing the following should fix your problem:
Return good_users from callposts()
Add a new variable to where you call callposts() in post_check() like
lowposters, good_users = await callposts(ctx)
So I finally figured this out, the script was looking at user.id as an attribute of user object. To fix that I had to use
elif str(user.id) in exempt): and elif str(user.id) in good_users:
#bot.command()
async def id(ctx, a:str): #a = #user
how would I get the ID of a user mentioned in the command, and output it as:
await ctx.send(id)
Use a converter to get the User object:
#bot.command(name="id")
async def id_(ctx, user: discord.User):
await ctx.send(user.id)
Or to get the id of the author:
#bot.command(name="id")
async def id_(ctx):
await ctx.send(ctx.author.id)
Just realized that when you #someone and store it to the variable "a", it contains the user ID in the form of '<#userid>'. So a bit of clean up can get me the user ID
Here's the code:
#bot.command()
async def id(ctx, a:str):
a = a.replace("<","")
a = a.replace(">","")
a = a.replace("#","")
await ctx.send(a)
Since my command consists of "rev id #someone", the #someone gets stored in 'a' as the string '<#userid>' instead of '#someone'.
If you want to handle a mention within your function, you can get the mention from the context instead of passing the mention as a string argument.
#bot.command()
async def id(ctx):
# Loop through the list of mentioned users and print the id of each.
print(*(user_mentioned.id for user_mentioned in ctx.message.mentions), sep='\n')
ctx.message.mentions will return:
A list of Member that were mentioned. If the message is in a private
message then the list will be of User instead.
When you loop through ctx.message.mentions, each item is a mentioned member with attributes such as id, name, discriminator. Here's another example of looping through the mentioned list to handle each member who was mentioned:
for user_mentioned in ctx.message.mentions:
# Now we can use the .id attribute.
print(f"{user_mentioned}'s ID is {user_mentioned.id}")
It's up to you whether you want to require the argument a as shown in the question above. If you do need this, note that the string will sometimes include an exclamation in the mention depending on whether it is:
for a User or command was posted from mobile app: <#1234567890>
for a Nickname or command was posted from desktop app: <#!1234567890>
Which is why I prefer to get the id from a member/user attribute.