discord.py block advertisment isnt working - python

I have recently started learning discord.py, and I am trying to remove certain links when they get posted in a channel. Please see my below code.
#Bot.event
async def on_message(message):
if "discord.gg" in message.content.lower():
await message.delete()
await message.channel.send("Luften Reklam Yapmaurn!")
await Bot.process_commands(message)

Here I have made a very basic link or word filter, it will look through the whole message for anything containing the specific key words specified below;
Depending if you also want to allow bots to send links, just remove the if message.author.bot: if not, keep it otherwise people may find they are limited to commands by other bots as they can't vote, etc. And depending on what links you want filtered can easily be customized in the "link_filter" array just below.
link_filter = [".com", "http", "https:", ".gg", "discord."]
#client.listen('on_message')
async def message(message, member: discord.Member = None):
if message.author.bot:
return
for word in link_filter:
if message.content.count(word) > 0:
await message.channel.purge(limit=1)
embed = discord.Embed(
colour = discord.Colour.red())
embed.set_footer(text=f"No links please!")
embed.add_field(name=f"NO links!", value=(message.author.mention) + ', Your message was deleted because it contained a link.', inline=False)
await message.channel.send(embed=embed, delete_after=10)

Related

How can I delete messages sent by a specific user within a specific channel using Discord.py

Hopefully this isn't a duplicate post but I've searched around and can't find anything on how to do this specifically.
I'm trying to create a Discord bot which can delete messages sent by a specific author, in a specific channel, but also checks previously sent messages.
At the moment I have the below, which adds new messages from chosen user to a list, checks if they're duplicates and if they are, deletes them.
I want to know:
A: How can I make this bot Channel specific
B: Can I have this program check old messages in that channel too and also delete them if they're duplicates?
Thanks in advance for any help and if any further info required, please let me know.
import discord
TOKEN = ('MY_TOKEN_LIVES_HERE')
client = discord.Client()
messagesSeen = []
#client.event
async def on_message(message):
if "News_Bot" in str(message.author):
if message.content in messagesSeen:
await message.delete()
else:
messagesSeen.append(message.content)
client.run(TOKEN)
Yes you can do both of those things. Since you are using on_message event you can just use message.channel to also check that channel for previously sent messages. I would also advise to change news_bot to the ID of the bot. The thing is one you implement this and clear the channel history for those messages, it won't be necessary anymore as the bot will catch the messages as soon as they are sent. So the message history is kind of a one time thing, which you can just create a cmd and run it in that channel.
messagesSeen = []
#client.event
async def on_message(message):
if 1234345 is message.author.id:
if message.content in messagesSeen:
await message.delete()
async for message in message.channel.history(limit=100):
if message.content in messagesSeen:
await message.delete()
else:
messagesSeen.append(message.content)

Discord py detect reactions

I am only trying to learn how to "read" the reaction on a message the same bot sends. I've been stuck for days. I looked it up but the only tutorials I find are with a specific message for roles. I don't care about that, I won't use a single message for the whole server, so there is no way I can get the ID for the message. I only want the bot to send a message, then the user reacts and the bot writes "you reacted with [emoji]".
I found some questions on this site, but they only managed to confuse me even more. Still, this is what I barely managed to make.
#bot.command()
async def react(ctx):
await ctx.send("React to me!")
#bot.event
async def on_reaction_add(reaction, user):
await channel.send("{}, you responded with {}".format(user, reaction))
There is actually a good example of this already in the documentation, you can find it here:
wait_for
But to simplify the whole thing a bit, here is a sample code:
#bot.command()
async def react(ctx):
def check(reaction, user): # Our check for the reaction
return user == ctx.message.author # We check that only the authors reaction counts
await ctx.send("Please react to the message!") # Message to react to
reaction = await bot.wait_for("reaction_add", check=check) # Wait for a reaction
await ctx.send(f"You reacted with: {reaction[0]}") # With [0] we only display the emoji
Here is how it looks like:
Without reaction[0] you would only get unnecessary information. [0] shows you only the first digit, in this case Reaction emoji.

How to snipe messages from a specific channel (discord.py)

Outcome
To snipe messages sent in X channel instead of all the channels within the Discord guild. That is, it should only track message deletions in that one channel (identified by its ID), and only respond to the !snipe command in that same channel. The current code I have here snipes every message sent within the Discord guild.
Question
How can I snipe messages sent in X channel instead of the entire guild?
I mostly intend to run this bot in one guild. However, it would be nice if it could scale to multiple guilds if needed.
The code I have so far is below.
import discord
from discord.ext import commands
from tokens import token
client = commands.Bot(command_prefix="!", self_bot=False)
client.sniped_messages = {}
#client.event
async def on_ready():
print("Your bot is ready.")
#client.event
async def on_message_delete(message):
print(f'sniped message {message}')
client.sniped_messages[message.guild.id] = (
message.content, message.author, message.channel.name, message.created_at)
#client.command()
async def snipe(ctx):
try:
contents, author, channel_name, time = client.sniped_messages[ctx.guild.id]
except:
await ctx.channel.send("Couldn't find a message to snipe!")
return
embed = discord.Embed(description=contents,
color=discord.Color.purple(), timestamp=time)
embed.set_author(
name=f"{author.name}#{author.discriminator}", icon_url=author.avatar_url)
embed.set_footer(text=f"Deleted in : #{channel_name}")
await ctx.channel.send(embed=embed)
client.run(token, bot=True)
I'm going to suggest two slightly different solutions, because the code can be simpler if you're only running this bot on one guild. What's common to both is that you need to check in what channel messages are deleted, and in what channel the !snipe command is sent.
Single-Guild Version
If you're only monitoring/sniping one channel on one guild, then you can only ever have one deleted message to keep track of. Thus, you don't need a dictionary like in your posted code; you can just keep a single message or None.
You're already importing your token from a separate file, so you might as well put the channel ID (which is an int, unlike the bot token) there too for convenience. Note that, by convention, constants (variables you don't intend to change) are usually named in all caps in Python. tokens.py would look something like this:
TOKEN = 'string of characters here'
CHANNEL_ID = 123456789 # actually a 17- or 18-digit integer
And the bot itself:
import discord
from discord.ext import commands
from tokens import TOKEN, CHANNEL_ID
client = commands.Bot(command_prefix='!')
client.sniped_message = None
#client.event
async def on_ready():
print("Your bot is ready.")
#client.event
async def on_message_delete(message):
# Make sure it's in the watched channel, and not one of the bot's own
# messages.
if message.channel.id == CHANNEL_ID and message.author != client.user:
print(f'sniped message: {message}')
client.sniped_message = message
#client.command()
async def snipe(ctx):
# Only respond to the command in the watched channel.
if ctx.channel.id != CHANNEL_ID:
return
if client.sniped_message is None:
await ctx.channel.send("Couldn't find a message to snipe!")
return
message = client.sniped_message
embed = discord.Embed(
description=message.content,
color=discord.Color.purple(),
timestamp=message.created_at
)
embed.set_author(
name=f"{message.author.name}#{message.author.discriminator}",
icon_url=message.author.avatar_url
)
embed.set_footer(text=f"Deleted in: #{message.channel.name}")
await ctx.channel.send(embed=embed)
client.run(TOKEN)
Multi-Guild Version
If you're monitoring one channel each in multiple guilds, then you need to keep track of them separately. Handily, channel IDs are globally unique, not just within a single guild. So you can keep track of them by ID alone, without having to include the guild ID as well.
You could keep them in a list, but I recommend a set, because checking whether something is in a set or not is faster. Comments to help yourself remember which one is which are probably also a good idea.
TOKEN = 'string of characters here'
# Not a dictionary, even though it uses {}
CHANNEL_IDS = {
# That one guild
123456789,
# The other guild
987654322,
}
Then instead of checking against the single channel ID, you check if it's in the set of multiple IDs.
import discord
from discord.ext import commands
from tokens import TOKEN, CHANNEL_IDS
client = commands.Bot(command_prefix='!')
client.sniped_messages = {}
#client.event
async def on_ready():
print("Your bot is ready.")
#client.event
async def on_message_delete(message):
# Make sure it's in a watched channel, and not one of the bot's own
# messages.
if message.channel.id in CHANNEL_IDS and message.author != client.user:
print(f'sniped message: {message}')
client.sniped_messages[message.channel.id] = message
#client.command()
async def snipe(ctx):
# Only respond to the command in a watched channel.
if ctx.channel.id not in CHANNEL_IDS:
return
try:
message = client.sniped_messages[ctx.channel.id]
# See note below
except KeyError:
await ctx.channel.send("Couldn't find a message to snipe!")
return
embed = discord.Embed(
description=message.content,
color=discord.Color.purple(),
timestamp=message.created_at
)
embed.set_author(
name=f"{message.author.name}#{message.author.discriminator}",
icon_url=message.author.avatar_url
)
embed.set_footer(text=f"Deleted in: #{message.channel.name}")
await ctx.channel.send(embed=embed)
client.run(TOKEN)
Note: bare except clauses, like in your original code, are not generally a good idea. Here we only want to catch KeyError, which is what is raised if the requested key isn't in the dictionary.
You could, optionally, implement the same logic in a different way:
message = client.sniped_messages.get(ctx.channel.id)
if message is None:
await ctx.channel.send("Couldn't find a message to snipe!")
return
A dictionary's .get() method returns the corresponding item just like normal indexing. However, if there is no such key, instead of raising an exception, it returns a default value (which is None if you don't specify one in the call to get).
If you're using Python 3.8+, the first two lines could also be combined using an assignment expression (using the "walrus operator"), which assigns and checks all at once:
if (message := client.sniped_messages.get(ctx.channel.id)) is None:
await ctx.channel.send("Couldn't find a message to snipe!")
return
These alternative options are mentioned for completeness; all of these ways of doing it are perfectly fine.

(Discord.py) Send a message to all guilds

I've been trying to send the same message to all the guilds where my bot is, but nothing has worked and I haven't been able to find something similar in the docs. Is this posible? How can I do It?
Edit: ok, lets's imagine that what my bot does is checking a news webpage like BBC or any other. The bot would be checking the web every five minutes and sending links of the news to those guilds where .start (for example) was executed. The way I've implemented this, was by a command that generates a single loop for each guild, the idea was to have just one loop for every guild.
for guild in bot.guilds:
await guild.text_channels[0].send(<message>)
This will get the first text channel found in the guild and send a message to it.
You can get the bot from a context variable by typing ctx.bot.
class send_all(commands.Cog):
def __init__(self,bot):
self.bot = bot
#commands.command()
async def send(self,ctx,*message_to_send):
guild = ctx.message.guild
output = ' '
author = ctx.message.author
for word in message_to_send:
output += word
output += ' '
for member in self.bot.get_all_members():
try:
embed = discord.Embed(title="",colour = discord.Colour.green())
embed.add_field(name="**From server:**",value= guild.name)
embed.add_field(name = "**From Mod/Admin:**",value = author.name)
embed.add_field(name="**Message:**",value = output)
# await ctx.send(embed=embed)
await member.send(embed=embed)
except (discord.HTTPException, discord.Forbidden,AttributeError):
continue

Discord.py --> channel.mention

I'm trying to make a bot for a discord server that simply listens for specific messages, deletes them and then refers the user to a different text channel (in a clickable link by mentioning it)
Here's what I have now:
import Discord
import asyncio
client = discord.Client()
#client.event
async def on_message(message):
msg = '{0.author.mention}\nWrong text channel\nUse '.format(message)
if message.content.startswith('!p'):
await client.delete_message(message)
await client.send_message(message.channel, msg)
return
client.run('')
Ideally, I'd also want to search through a list with startswith() instead of just ('!p') & to ignore all messages from a specific text channel as well but I'm not sure how to do those either
Don't know if your problem is solved or not, but for all future developers looking on this thread. A super simple way to get a bot to mention a channel is like this...
<#channelID>
were the channel ID is the discord ID of the specific channel you wish to mention.
and in an example
await message.channel.send("Please go to <#channelID>")
I'm honestly a bit confused that no one on this thread has already mentioned this, so I feel like I'm missing something that y'all already know lol.
Sure, just add text_channel = client.get_channel('1234567890') and reference its mention with text_channel.mention (where 1234567890 is the id of the channel you want to link to)
So the code would end up looking something like this
#client.event
async def on_message(message):
text_channel = client.get_channel('1234567890')
msg = '{0.author.mention}\nWrong text channel\nUse {1.mention}'.format(message,text_channel)
if message.content.startswith('!p'):
await client.delete_message(message)
await client.send_message(message.channel, msg)
return
Regarding your second question, you could do something like this
arr = ['!p','!a','!b']
for a in arr:
if message.content.startswith(a):
break
else:
return
and remove the if message.content.startswith('!p'): altogether
To ignore a specific channel just do if message.channel.id == "9876543210": at the top of the function (9876543210 is the id of the channel you want to ignore commands from)
With those changes the code looks like this
#client.event
async def on_message(message):
if message.channel.id == "9876543210":
return
arr = ['!p','!a','!b']
for a in arr:
if message.content.startswith(a):
break
else:
return
text_channel = client.get_channel('1234567890')
msg = '{0.author.mention}\nWrong text channel\nUse {1.mention}'.format(message,text_channel)
await client.delete_message(message)
await client.send_message(message.channel, msg)
return
import discord
from discord.ext import commands
client = commands.Bot(command_prefix='>')
#client.event
async def on_ready():
print("Log : "+str(client.user))
#client.command()
async def mention(ctx):
ch = await client.fetch_channel(enter channel id)
await ctx.send(f"Mention your channel -> {ch}")
client.run("token")

Categories