Discord.py making bot respond in certain channels - discord

I want the users with my bot to be able to configure the bot to only run in certain channels. I was able to achieve this when I was using the on_message function by checking which channel the message was coming from. Now I'm using Cogs and I'm not sure how I would approach this problem.
My Old Code was something like this:
val_channels = ['a', 'b', 'c']
if message.channel in val_channels:
# Do Something
else:
print('The bot was configured to: ' + ', '.join(val_channels))

You can verify if the ctx.message.channel.id matches with your list.
class Greetings(commands.Cog):
#commands.command()
async def hello(self, ctx):
"""Says hello"""
if ctx.message.channel.id in val_channels:
await ctx.send('Hello!')
else:
await ctx.send('You can not use this command here.')
But if you still want to use a on_message event inside a cog, you will need do modify the decorator. Link to doc
class Greetings(commands.Cog):
#commands.Cog.listener()
async def on_message(self, message):
if message.channel.id in val_channels:
# Do something
else:
print('The bot was configured to: ' + ', '.join(val_channels))

Related

How can I have a trigger without my command prefix, like welcome and not $welcome?

So I wanted to make a feature on my discord bot and I wanted it to respond when users say welcome and say Welcome! back. But every time I try it only responds to $welcome. ($ is my prefix). What should I do?
client = commands.Bot(command_prefix = "$")
#client.command()
async def welcome(ctx, message):
if any(word in message for word in welcome):
await message.channel.send("Welcome!")
#client.event
async def on_message(message):
if "welcome" in message.content:
await message.channel.send('Welcome!')

How to prevent bot from spamming embeds? Discord.py

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.

Discord.py bot react to user's next message after using a specific command

For example:
I use !react command and then after 1 min I send a message and then the bot reacts to the message with a specific emoji. Is it possible?
#commands.command()
#commands.cooldown(1, 600, commands.BucketType.user)
async def cookieme(self, ctx):
...somehow remembers to this name and next time the user say something it reacts to the msg with a cookie
I don't really understand your question but I will try to help you:
#bot.command()
async def react(ctx):
def check(message):
return ctx.author == message.author and ctx.channel == message.channel
react = await bot.wait_for("message", check=check)
await react.add_reaction("🍪")

how to add reaction to a specifc user?

I've been working on this piece of code:
#client.event
async def lol(message,ctx):
if ctx.author.id == <user_id>:
await message.add_reaction('❤️')
else:
return
I am pretty sure that it is developed correctly, yet I am not getting the desired results.
I am pretty sure that if you check the console, an HTTP error would have been encountered. That's because you directly pasted the emoji in the function parameter. You have to add its unicode value. In your case:
await message.add_reaction(u'\u2764')
You are using an event decorator rather than a command, unless you were trying to detect if the user reacted, but its still completely off. What it looks like, the command that is called will send a message and the bot will react to it.
#client.command()
async def lol(ctx):
message = await ctx.send(f"{ctx.author.mention}, lol")
await message.add_reaction('😂')
If you then want to detect if the user had reacted to the emoji, you can use a event, but an on_reaction_add:
#client.event
async def on_reaction_add(reaction, user):
if reaction.emoji == '😂':
await user.send("Lol")

Discord Python Rewrite - Broadcast

Is it possible to make the bot sends 1 message on every server that the bot is in without sending the message to every channel? I have a working code but it sends to all channel
#client.command()
async def broadcast(ctx, *, message):
for guild in client.guilds:
for channel in guild.channels:
if guild.name == ctx.author.guild.name:
pass
else:
try:
await channel.send(message)
await ctx.send(
'Sent to {} (ID: {}, Owner: {}#{} With {} Members)'.format(
guild.name,
guild.id,
guild.owner.name,
guild.owner.discriminator,
guild.member_count
))
except:
await ctx.send(
'Could not send at {} (Channel ID: {}). (Owner: {}#{})'.format(
guild.name,
channel.id,
guild.owner.name,
guild.owner.discriminator,
))
return
else:
break
please help
If you use
for guild in client.guilds:
channel = discord.utils.get(guild.text_channels, name="general")
if channel != None:
#do something
you could get the #general channel from each guild. That would be just one channel (Discord allows multiple channels to share names but most people won't do this, and .get() will return the first only, anyway).
This is much better than looping over all channels and slightly better than picking random channels but I still would consider letting guilds set their own broadcast reception channels.
Tested and it works, albeit my bot exists only in one server, I don't know if there are unknown consequences for trying to do this over 100+ servers.

Resources