The user is successfully muted if the bot detects "discord" in the custom signature.
When user remove discord from custom signature, he not unmuted.
The else part of the code is completely ignored because I get no message/no error, it continue the loop ...
So, where i'm wrong in my code?
```#tasks.loop(seconds=10)
async def status_role():
# ID guild
guild = client.get_guild(1234567890)
staff = discord.utils.get(guild.roles, name="Staff")
role1 = discord.utils.get(guild.roles, name='Bot')
muted = discord.utils.get(guild.roles, name="Muted")
for member in guild.members:
memberActivity = member.activity
if memberActivity:
# if staff or bo bot role => ignore both
if staff in member.roles or role1 in member.roles:
continue
nameOfActivity = memberActivity.name
# if discord is present in username of user
if "discord" in nameOfActivity:
# if already muted, continue
if muted in member.roles:
continue
else:
# if not muted => mute user
await member.add_roles(muted)
continue
else:
# if discord is not present in username of user
if "discord" not in nameOfActivity:
# if user is muted, do remote mute below
if muted in member.roles:
await member.remove_roles(muted)
print('muted removed')
continue
print(status_role.current_loop)```
Im using google translate, sorry if my english is bad...
Discord rewrite:2.0.0a
Python 3.9
Windows 10 x64
Thanks for your help
Ok, i assume your comments were correct. You need to remove 4 spaces from each of these lines:
else:
# if discord is not present in *username* of user
if "discord" not in nameOfActivity:
# if user is muted, do remote mute below
if muted in member.roles:
await member.remove_roles(muted)
print('muted removed')
continue
Or in other words, remove one indent, this block triggers when if "discord" in nameOfActivity: fails, but it should trigger when if memberActivity: fails, at least i assume.
Related
trying to make a small bot for my server. it kinda works but if the user removes the nickname, the bot returns a None value. how can i fix this?
the goal is to have a bot detect if a user has TBU in the nickname or username, if it does, add him to a role in discord (havnt added this yet, need to look into it) but if the change removes TBU in the name, remove the role.
#client.event
async def on_member_update(before, after):
if before.nick != after.nick: # to only run on status
embed = discord.Embed(title=f"Changed nick")
embed.add_field(name='User', value=before.mention)
embed.add_field(name='Before', value=before.nick)
embed.add_field(name='After', value=after.nick)
# send to admin or channel you choose
channel = client.get_channel(526517582963146762) # notification channel
await channel.send(embed=embed)
admin = client.get_user(174749290902716417) # admin to notify
await admin.send(embed=embed)
if "TBU" in after.nick:
admin = client.get_user(174749290902716417) # admin to notify
await admin.send(embed=embed)
if "TBU" in before.nick and not "TBU" in after.nick:
admin = client.get_user(174749290902716417) # admin to notify
await admin.send(embed=embed)
When a user has no nickname nick returns None.
Change if before.nick != after.nick to if before.nick != after.nick and after.nick is not None, this should work.
I'm trying to get it so a specific role can react to the message to be able to ban the user, I have made the ability to be able to react to the message, and the author of the command can ban the user, but I want to make it so another role can do it as well
Here is what I have currently
def check(rctn, user):
return user.id == ctx.author.id and str(rctn) == '<:tick:837398197931868190>'
reaction, user = await bot.wait_for('reaction_add', check=check)
You can use #commands.has_permissions
For example you could make it:
#bot.command()
#commands.has_permissions(ban_members=True)
# rest of your code
This way only roles with the permissions to ban_members can use the command
I have discord bot and it checks whether streamer is live or not. And I have a function that prevents it from spamming when someone is live:
if status is True:
async for message in channel.history(limit=2000):
if message.content == f"`Hey #everyone, {twitch_name} is live! Check it out:" + f"https://www.twitch.tv/{twitch_name}`":
break
else:
async for member in guild.fetch_members(limit=None):
if member.id == int(user_id):
await member.add_roles(role)
await channel.send(f"`Hey #everyone, {twitch_name} is live! Check it out:" + f"https://www.twitch.tv/{twitch_name}`")
print(f"{user} started streaming. Sending a notification.")
break
And I wonder if there is the way to do same with embeds, but idk what to use. I though I can use if embed = twitch_embed: break instead of if message.content.
I want to send both message and embed when someone is live one time per stream each like mee6 does:
And I want to combine message and embed antispam function in the code. Please help! All my code here if you need:
import os
import json
import discord
import requests
from discord.ext import tasks, commands
from server import ping
from twitchAPI.twitch import Twitch
from discord.utils import get
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='$', intents=intents)
# Authentication with Twitch API.
client_id = os.getenv('client_id')
client_secret = os.getenv('Dweller_token')
twitch = Twitch(client_id, client_secret)
twitch.authenticate_app([])
TWITCH_STREAM_API_ENDPOINT_V5 = "https://api.twitch.tv/kraken/streams/{}"
API_HEADERS = {
'Client-ID': client_id,
'Accept': 'application/vnd.twitchtv.v5+json',
}
user_info = twitch.get_users(logins=['turb4ik'])
user_id = user_info['data'][0]['id']
print(user_info)
# Returns true if online, false if not.
def checkuser(user):
try:
userid = twitch.get_users(logins=[user])['data'][0]['id']
url = TWITCH_STREAM_API_ENDPOINT_V5.format(userid)
try:
req = requests.Session().get(url, headers=API_HEADERS)
jsondata = req.json()
if 'stream' in jsondata:
if jsondata['stream'] is not None:
return True
else:
return False
except Exception as e:
print("Error checking user: ", e)
return False
except IndexError:
return False
# Executes when bot is started
#bot.event
async def on_ready():
# Defines a loop that will run every 10 seconds (checks for live users every 10 seconds).
#tasks.loop(seconds=10)
async def live_notifs_loop():
# Opens and reads the json file
with open('streamers.json', 'r') as file:
streamers = json.loads(file.read())
# Makes sure the json isn't empty before continuing.
if streamers is not None:
# Gets the guild, 'twitch streams' channel, and streaming role.
guild = bot.get_guild(690995360411156531)
channel = bot.get_channel(785523710362124298)
role = get(guild.roles, id=835581408272580649)
# Loops through the json and gets the key,value which in this case is the user_id and twitch_name of
# every item in the json.
for user_id, twitch_name in streamers.items():
print("checking" + " " + str(twitch_name))
# Takes the given twitch_name and checks it using the checkuser function to see if they're live.
# Returns either true or false.
status = checkuser(twitch_name)
# Gets the user using the collected user_id in the json
user = bot.get_user(int(user_id))
# Makes sure they're live
if status is True:
# Checks to see if the live message has already been sent.
#limit = 0
#limit += 1
async for message in channel.history(limit=2000):
# If it has, break the loop (do nothing).
if message.content == f"`Hey #everyone, {twitch_name} is live! Check it out:" + f"https://www.twitch.tv/{twitch_name}`":
break
# If it hasn't, assign them the streaming role and send the message.
else:
# Gets all the members in your guild.
async for member in guild.fetch_members(limit=None):
# If one of the id's of the members in your guild matches the one from the json and
# they're live, give them the streaming role.
if member.id == int(user_id):
await member.add_roles(role)
# Sends the live notification to the 'twitch streams' channel then breaks the loop.
'''twitch_embed = discord.Embed(
title=f":red_circle: **LIVE**\n{user.name} is now streaming on Twitch!",
color=0xac1efb
)'''
#twitch_embed.add_field(name='**Game**', value='add value',inline=True)
#twitch_embed.add_field(name='**Viewers**', value='add value',inline=True)
#twitch_embed.set_image(url=f'\nhttps://www.twitch.tv/{twitch_name}')
await channel.send(f"`Hey #everyone, {twitch_name} is live! Check it out:" + f"https://www.twitch.tv/{twitch_name}`")
#await channel.send(embed=twitch_embed)
print(f"{user} started streaming. Sending a notification.")
break
# If they aren't live do this:
else:
# Gets all the members in your guild.
async for member in guild.fetch_members(limit=None):
# If one of the id's of the members in your guild matches the one from the json and they're not
# live, remove the streaming role.
if member.id == int(user_id):
await member.remove_roles(role)
# Checks to see if the live notification was sent.
async for message in channel.history(limit=200):
# If it was, delete it.
if str(user.mention) in message.content and "is now streaming" in message.content:
await message.delete()
# Start your loop.
live_notifs_loop.start()
# Command to add Twitch usernames to the json.
#bot.command(name='addtwitch', help='Adds your Twitch to the live notifs.', pass_context=True)
#commands.has_permissions(administrator = True)
async def addtwitch(ctx, twitch_name):
# Opens and reads the json file.
with open('streamers.json', 'r') as file:
streamers = json.loads(file.read())
# Gets the users id that called the command.
user_id = ctx.author.id
# Assigns their given twitch_name to their discord id and adds it to the streamers.json.
streamers[user_id] = twitch_name
# Adds the changes we made to the json file.
with open('streamers.json', 'w') as file:
file.write(json.dumps(streamers))
# Tells the user it worked.
await ctx.send(f"Added {twitch_name} for {ctx.author} to the notifications list.")
ping()
bot.run(os.getenv('token'))
Edit:
Please say if something is not right or you don't understand the question instead of just closing it.
To send the embed in the same message you can use content an example would be:
await channel.send(content=f"`Hey #everyone, {twitch_name} is live! Check it out:" + f"https://www.twitch.tv/{twitch_name}`", embed=twitch_embed)
There would be no change in your check function as the message.content would be the same text message just with an embed as well.
You should really check if the stream has finished either by web scraping or some API instead of checking message content. If the stream finishes 3 hours ago but you only check for 2 streamers there won't be a change unless you have thought of this already.
I've got this code for my discord bot, which can ban people and DM them the reason for the ban first.
cooldown = []
#bot.command(pass_context = True)
#commands.has_role('Senior Moderator')
async def ban(ctx, member: discord.Member = None, *, reason = None):
author = str(ctx.author)
if author in cooldown:
await ctx.send('Calm down! You\'ve already banned someone less than two hours ago.')
return
try:
if reason == None:
reason = 'breaking the rules.'
await member.send(f'You have been banned from **{ctx.guild.name}** for **{reason}**')
await member.ban(reason = f"Banned by {ctx.message.author} for "+reason)
await ctx.send(f'{member.mention} has been banned.')
cooldown.append(author)
await asyncio.sleep(2 * 60 * 60) #The argument is in seconds. 2hr = 7200s
cooldown.remove(author)
except:
await ctx.send('Error. Please check you are typing the command correctly. `!ban #username (reason)`.')
However, if the user I am trying to ban has DM's disabled, the bot can't send the ban reason message, so therefore doesn't proceed to the next step, which is banning them, and returns the error message, which is Error. Please check you are typing the command correctly. !ban #username (reason)
Please can you rewrite the code to allow it to try to DM someone the reasoning before banning them, but if they have DM's disabled, it shall still ban them anyway. Thank you!
By simply moving the ban to be executed first (as it is a priority), then it will attempt to dm the user.
I also re-adjusted some parts of the code. It will now try to send a dm, if not, it will still ban but a message will be sent to the channel alerting a message was not sent to the banned user.
#bot.command(pass_context = True)
#commands.has_role('Senior Moderator')
async def ban(ctx, member: discord.Member = None, *, reason = None):
author = ctx.author
if author in cooldown:
await ctx.send('Calm down! You\'ve already banned someone less than two hours ago.')
return
if member == None:
await ctx.send('Please mention a member to ban!')
return
if reason == None:
reason = 'breaking the rules.'
await member.ban(reason = f"Banned by {ctx.message.author} for " + reason)
try:
await member.send(f'You have been banned from **{ctx.guild.name}** for **{reason}**')
except:
await ctx.send(f'A reason could not be sent to {ctx.message.author} as they had their dms off.')
await ctx.send(f'{member.mention} has been banned.')
cooldown.append(author)
await asyncio.sleep(2 * 60 * 60)
cooldown.remove(author)
I too noticed the same thing when I first made my bot ban command, I did the following to fix my ban command. First I tried a scenario where the bot could dm the user, if it can, then It will dm the user and then ban the user (Note: Do not ban the user before DMing the user as the bot can only DM the user when the user and the bot share a common server). However, I then made an Exception that if the bot couldn't dm the user, it will send a message in the channel the command was executed "Couldn't dm the user" then ban the user
try:
await member.send(embed=embo)
await ctx.guild.ban(member, reason=reason)
except Exception:
await ctx.send("Couldn't send dm to the user")
await ctx.guild.ban(member, reason=reason)
EDIT:
you can also opt for the following:
try:
await member.send(embed=embo)
await ctx.guild.ban(member, reason=reason)
except discord.HTTPException:
await ctx.send("Couldn't send dm to the user")
await ctx.guild.ban(member, reason=reason)
before I specified this, I encountered the following error.
I fixed it, afterward, adding the exception case.
So modern documentation on the bot.wait_for() coroutine is not super detailed, and I'm having trouble getting it to work with reactions. Would appreciate feedback.
Python 3 with Discord.py
## Test Role Add
#kelutralBot.command(name='testreaction')
async def testReaction(ctx):
member = ctx.message.author
message = await ctx.send("This is a test message.")
emojis = ['\u2642','\u2640','\u2716']
for emoji in emojis:
await message.add_reaction(emoji)
def check(reaction, user):
return user == message.author and str(reaction.emoji) == '\u2642'
try:
reaction, user = await kelutral.wait_for('reaction_add', timeout=60.0, check=check)
except asyncio.TimeoutError:
await ctx.send("Window has passed to self-assign pronouns. Please DM a mod if you would still like to do so.")
else:
print(reaction)
male = get(member.guild.roles, name="He/Him")
await member.add_roles(male)
print("Assigned " + member.name + " He/Him pronouns.")
Two things were wrong.
First, don't use Client and Bot in the same command. Bot is sufficient for both.
Second, Unicode Emoji for Discord are treated as '\U000#####', which was the biggest problem.
Once we solved that, everything worked as intended.
The problem here is that you are checking if the person who sent the reaction is the author of the message that contains the message, which is only satisfied by the bot that reacted. Also consider using a role ID instead (server settings > roles > left click role > right click role > copy ID). You also want to be consistent with kelutral or kelutral Bot throughout the command.
#kelutralBot.command(name='testreaction')
async def testReaction(ctx):
member = ctx.message.author
message = await ctx.send("This is a test message.")
emojis = ['\u2642','\u2640','\u2716']
for emoji in emojis:
await message.add_reaction(emoji)
def check(reaction, user):
return user == member and str(reaction.emoji) == '\u2642' # check against the member who sent the command, not the author of the message
try:
reaction, user = await kelutralBot.wait_for('reaction_add', timeout=60.0, check=check)
except asyncio.TimeoutError:
await ctx.send("Window has passed to self-assign pronouns. Please DM a mod if you would still like to do so.")
else:
print(reaction)
male = ctx.message.guild.get_role(ROLE_ID_GOES_HERE) # put your role ID here #
await member.add_roles(male)
print(f"Assigned {member.name} He/Him pronouns.")
Keep in mind your code only works for the "male" role, you have to implement a different check function to use it for everything.