Command to spam something discord-bot - discord.py

so basically I am trying to make a spam command for my discord bot, which takes in a custom message to spam. Here's the code:
#client.command(name='spam')
async def spam(ctx):
global stop
stop = 0
content = ctx.message.content[11:]
if ctx.author.guild_permissions.administrator or ctx.author.id in admins:
if lock == 1:
await ctx.send('Jesus bot is currently locked.')
elif lock == 0:
await ctx.send('Beginning spam..')
while not stop:
await ctx.send(content)
else:
await ctx.send('Sorry, but you do not have admin permissions in this server, or you are not a verified admin.')
For some reason, whenever I try to use this command, the bot doesn't respond. I'm not sure why this happens, and could use some help please.
Picture of bot not responding:

I have a spam command, but I only use it to mess around with my friends. I would not recommend using this as a public command, as you may get rate limited or banned for abuse or something like that. Anyway here is the code I have used for it.
#commands.command()
#commands.is_owner()
# If you want to use admin only, use this below
# #commands.has_permissions(administrator=True)
async def spam(self, ctx, amount, *, word):
int(amount)
await asyncio.sleep(2)
print(f"Starting to spam {word} in {ctx.guild.name}")
await ctx.message.delete()
await ctx.send(f"{ctx.author.mention}\nPlease note that this will clog up the bot's reaction time")
await asyncio.sleep(3)
count = 0
counting=True
while counting:
await ctx.send(word)
count = count + 1
if count == amount:
await asyncio.sleep(2)
await ctx.send("Spam complete")
print(Fore.GREEN + "Spam complete")
counting = False
At the top of your code, make sure you import asyncio as time.sleep will cause the whole bot to pause. Also the Fore.GREEN stuff is just colorama (import colorama).

Try using tasks instead of asyncio. It is made for such repetetive operations and it is easier and nicer because it is made by discord and is included in discord.ext. Something like this:
from discord.ext import tasks
#client.command(name='spam')
async def spam(ctx):
#get message and do all the ifs that you have there
spamLoop.start()
#client.command(name='stopSpam')
async def spamStop(ctx):
# stop the loop
spamLoop.cancel()
#tasks.loop(seconds=1)
async def spamLoop():
print("The message")

Actually quite a simple way of adding spam
import asyncio
#bot.command(name='spam', help= "Spam to your heart's delight")
async def spam(ctx, thing, amount):
count = 0
while count < int(amount):
await ctx.send(thing)
count += 1
if count < amount:
await asyncio.sleep(1)

Related

Nextcord typing through discord bot

I would like to be able to asynchronously send inputs to my python terminal and have my bot output them, whilst also keeping my other event running.
import nextcord
import botToken #contains the string of my bot token
from nextcord.ext import commands
client = commands.Bot(command_prefix="!")
#client.event
async def on_ready():
general = client.get_channel(925388635304521859)
while True:
inp = input("->")
if len(inp) < 4001:
await general.send(inp)
else:
await general.send(inp[0: 1500])
#client.event
async def on_message(message): #its supposed to react to each message with a buffalo emoji
print(message.content)
channel = message.channel
if "<#!308022163330564099>" in message.content:
await message.delete()
await channel.send("🐃")
await message.add_reaction("🐃")
client.run(botToken.TOKEN)e
Currently the on_ready() event only loads when it starts which is good, but i would like it to be asyncronic if thats a possibility. I don't know much about nextcord so I have no ideas. I would love any ideas for this.
The tasks extension in Nextcord may help for what you are trying to do
https://nextcord.readthedocs.io/en/latest/ext/tasks/index.html
It allows you to execute code in the background using a loop.
from nextcord.ext import tasks
#tasks.loop(seconds=1.0)
async def my_task_loop():
print("Hello!")
#my_task_loop.before_loop
async def before_my_task_loop():
print('waiting for ready')
await self.bot.wait_until_ready()
my_task_loop.start()

How to change channel permissions without having a message sent first?

I have a program that changes what channel members can see at certain times of the day. To do this, I can either change the roles that every member has, or change the permissions of each channel. However, I have looked all over the web and all of the ways for either method require a message to be sent so that the data from that message can be read and put into the function, such as:
#client.command()
async def perm(ctx):
await ctx.channel.set_permissions(ctx.guild.default_role, send_messages=False
Change the permissions of a discord text channel with discord.py
or
async def addrole(ctx):
member = ctx.message.author
role = get(member.server.roles, name="Test")
await bot.add_roles(member, role)
Discord.py | add role to someone
My current program looks like this:
import discord
client = discord.Client()
import datetime
async def live_day(schedule):
current_place = "the void"
while True:
current_time = str((datetime.datetime.now() -datetime.timedelta(hours=7)).time())
int_time = int(current_time[:2] + current_time[3:5])
for x in range(len(schedule)):
try:
start_time = schedule[x][1]
end_time = schedule[x + 1][1]
except IndexError:
end_time = 2400
if current_place != schedule[x][0] and int_time >= start_time and int_time < end_time:
current_place = schedule[x][0]
#Change the channel permissions of the current place to allow viewing
#Change the channel permissions of the last channel to disallow viewing
#client.event
async def on_ready():
print("{0.user} has arrived for duty".format(client))
client.loop.create_task(live_day([
("Home", 0),
("Work", 900),
("Home", 1700),
("Nightclub", 2000),
("Home", 2200),
]))
client.run(my_secret)
Never mind the badly written code, how would I do this or where should I go to figure this out? Any help is appreciated. Thanks!
Edit: I could get the channels individually by using this,
channel1=client.get_channel(channelid)
discord.py, send message by channel id without on_message() event?
but then I can't use this for more than one server. How can I get channels by name?
Note on on_ready():
This function is not guaranteed to be the first event called. Likewise, this function is not guaranteed to only be called once. This library implements reconnection logic and thus will end up calling this event whenever a RESUME request fails.
Using this function may crash the bot.
Instead create background tasks and use wait_until_ready().
You can find examples in https://github.com/Rapptz/discord.py/blob/v1.7.3/examples/background_task.py
If you want to change only one channel's permissions (per guild) this might fit your needs:
#changing "Home" channel visibility, every day at 5 pm.
#client.event
async def on_ready():
while True:
await asyncio.sleep(1)
current_time = datetime.datetime.now()
five_pm = current_time.replace(hour=17, minute=0, second=0)
if current_time == five_pm:
for guild in client.guilds: #looping through all the guilds your bot is in
channel = discord.utils.get(client.get_all_channels(), name="Home") #getting channel by name by using "discord.utils"
await channel.set_permissions(guild.default_role, view_channel=True) #changing permissions
By using the on_ready() event you can loop through the time check without sending any message.
Remember to import discord.utils.

Discord bot repeating the command but not an event in discord.py

I want to ask something.I got stuck on something.I wanted to add some new features to my bot such as swear words so that making cleaner server.I finished my code and tried to give command which is !dc greetings(!dc is my command_prefix btw).My bot sent 'Hi everyone' message for 7 times.That 7 times is same number as the number of swear words in "Badwords.txt".By looking these,that repeating issue is related to this file handling codes(or not idk).Interesting thins is when I write swear word into server's chatbox,bot send only one "Please do not use this word ever" message.So How can i prevent bot not to repeat for many times?Thank you
import discord
from discord.ext import commands
intents = discord.Intents(messages=True, guilds=True, reactions=True, members=True,presences=True)
client = commands.Bot(command_prefix="!dc ", intents=intents)
#Below command gets repeated 7 times everytime.That number is same as the number of swear words in "Badwords.txt"
#client.command(aliases=["sayHi"])
async def greetings(ctx):
await ctx.send('Hi everyone')
#My purpose in the below codes is countering profanity
with open("Badwords.txt", "r", encoding="utf-8") as f:
word = f.read()
badwords = word.split(",")
#In the below event,bot sends message only 1 time for 1 message
#client.event
async def on_message(message):
msg = message.content
for x in badwords:
if x in msg:
await message.delete()
await message.channel.send("Please do not use this word ever")
else:
await client.process_commands(message)
client.run(Token)
I would take the await client.process_commands(message) out of the else statement. I have also moved the with open inside the on message event so everything a message is sent, it will open the file to check if the message contained a bad word.
import discord
from discord.ext import commands
intents = discord.Intents(messages=True, guilds=True, reactions=True, members=True,presences=True)
client = commands.Bot(command_prefix="!dc ", intents=intents)
#client.command(aliases=["sayHi"])
async def greetings(ctx):
await ctx.send('Hi everyone')
#client.event
async def on_message(message):
msg = message.content
with open("Badwords.txt", "r", encoding="utf-8") as f:
word = f.read()
badwords = word.split(",")
for x in badwords:
if x in msg:
await message.delete()
await message.channel.send("Please do not use this word ever")
else:
return
await client.process_commands(message)
client.run(Token)
await client.process_commands(message) was taken out of the else statement because, with your current code, the bot would only process the commands if the message did NOT contain a bad word. But we need it to process the commands every time a message is sent.

How do I take in user input in discord.py

This may be kinda dumb but I'm trying to make a purge command but theres always something wrong with it. Can anyone help please?
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('p!purge'):
numberoftimes = input(int('How many times: '))
await message.channel.purge(limit=str(numberoftimes))
I'll start with answering your question, then I'll clarify on a better way to create a purge command. To answer your question, there is no need to make an input() statement. Rather, this is how you make an input prompt with a Discord bot:
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('p!purge'):
await message.channel.send('How many messages do you want to purge?')
while True:
numberoftimes = client.wait_for('message') # This means, the client is waiting for a message
if numberoftimes.author == message.author: # Make sure that the person responding is the person who did the command
limit = int(numberoftimes.content) # If its a string, it will be treated as a word. You want to purge a "number" of messages
await message.channel.purge(limit=limit+1)
That's how you would purge messages in a channel. But, the way you are creating this command can be made simpler. You can use the command decorator, which is the "standard" way of doing things:
import discord
from discord.ext import commands
client = commands.Bot(command_prefix='p!')
#client.command()
#commands.has_permissions(manage_messages=True)
async def purge(ctx, limit):
limit = int(limit)
await ctx.channel.purge(limit=limit + 1)

get channel name and send a message over at that channel

So I am working on a little project here, and pretty much, I want to have one of those "Please type the name of a channel in this server" feature.
So pretty much, the bot asks for a channel name, and I put in for example "#changelog" - and then it will ask for what it should write in that channel, etc etc.
So need to get the channel id (I am guessing), but I don't want users to write the ID, instead only writing the #server-name. And then whenever I have done that, the bot shall write in that channel.
Here is my current code!
class Changelog(commands.Cog):
def __init__(self, client):
self.client = client
#commands.Cog.listener()
async def on_ready(self):
print('Changelog is loaded')
#commands.command()
async def clhook(self, ctx):
await ctx.send('Write text-channel: ')
text_channel = await self.client.wait_for("message", check=lambda message: message.author == ctx.author, timeout=300)
clhook = self.client.get_channel(text_channel)
def setup(client):
client.add_cog(Changelog(client))
Edit:
The channel ID shall be saved "forever", meaning that I do not have to re-write the channel name where the message should go!
You can use discord.utils.get() with this example:
text_channel = await self.client.wait_for("message", check=lambda message: message.author == ctx.author, timeout=300)
channel = discord.utils.get(ctx.guild.text_channels, name=text_channel)
await channel.send('Bla Bla')
So when you type (prefix)clhook then only the channel name, for example general, it will send Bla Bla to the channel named general .
There is another way to do this and I think it's simple than the first option, here it is:
#commands.command()
async def clhook(self, ctx, channel: discord.TextChannel):
await channel.send('Bla Bla')
So in this command, usage is changed. You can use that with this: (prefix)clhook #general(mention the channel). I suggest this solution and I think it's more useful.
You can use message.channel_mentions. This will return a list of all channels that were mentioned using the #channel-name notation. That way, you can just use channel.id to get the id of the channel they mentioned.
Don't forget, however, to check if the user did in fact tag a channel (which you can also put in your check). I put it in a separate function to make it a bit more readable for the sake of this reply, but you can fit that in your lambda if you really want to.
Also, make sure to check if it's a Text Channel and not a Voice Channel or Category Channel.
#commands.command()
async def clhook(self, ctx):
def check(self, message):
author_ok = message.author == ctx.author # Sent by the same author
mentioned_channel = len(message.channel_mentions) == 1 and isinstance(message.channel_mentions[0], discord.TextChannel)
return author_ok and mentioned_channel
await ctx.send("Write text-channel: ")
text_channel = await self.client.wait_for("message", check=check)
chlhook = text_channel.channel_mentions[0]
I put two conditions on the mentioned_channel line, because if the first one fails, the second one could cause an IndexError. Alternatively you can also use an if-statement to return sooner at that place to solve the same issue.

Resources