I'm trying to get my background task to send in different channels using random.choice(). When I turn the bot on, it will send in only one random channel and that channel only. Is there a way to send in a different channel each time it loops?
async def test_loop():
await client.wait_until_ready()
channels = ['550528972226', '5149003563352', '514900351233', '5799132312340']
channel = client.get_channel(random.choice(channels))
while not client.is_closed:
time = random.randint(1,5)+random.random()
monies = random.randint(100,250)
emojigrab = dollar
emojimsg = await client.send_message(channel, emojigrab)
await client.add_reaction(emojimsg, hand)
pay = await client.wait_for_reaction(emoji=hand, message=emojimsg, timeout=1800,
check=lambda reaction, user: user != client.user)
if pay:
await client.delete_message(emojimsg)
await client.send_message(channel, "{} collects {:,} dollars".format(pay.user.mention, monies))
add_dollars(pay.user, monies)
await asyncio.sleep(int(time))
Currently, channel = client.get_channel(random.choice(channels)) is outside of your while loop, meaning that variable channel never changes. Move it to inside your while loop to change it every time a new message is going to be sent.
async def test_loop():
await client.wait_until_ready()
channels = ['550528972226', '5149003563352', '514900351233', '5799132312340']
while not client.is_closed:
channel = client.get_channel(random.choice(channels))
time = random.randint(1,5)+random.random()
monies = random.randint(100,250)
emojigrab = '💵'
emojimsg = await client.send_message(channel, emojigrab)
await client.add_reaction(emojimsg, "💰")
pay = await client.wait_for_reaction(emoji="💰", message=emojimsg, timeout=1800,
check=lambda reaction, user: user != client.user)
if pay:
await client.delete_message(emojimsg)
await client.send_message(channel, "{} secures the bag for ${:,}".format(pay.user.mention, monies))
add_dollars(pay.user, monies)
await asyncio.sleep(int(time))
Related
Im currently trying to make the reaction in the bot response to turn off an moderation event which listens to messages being deleted. This will work as a filter so if the user dont want to log deleted messages they can turn it off by reacting. I've heard of the wait for and the dispatch function but i currently dont know how it works and couldnt find a tutorial. Any feedback would be amazing as i am a bit stuck and willing to listen to anyone.
Current Code;
import discord
from discord.ext import commands
import datetime
class log(commands.Cog):
def __init__(self,bot):
self.bot = bot
mess = False
#commands.Cog.listener()
async def on_reaction_add(self, reaction, user):
channel = reaction.message.channel
guild = channel.guild
message = reaction.message
if user != self.bot.user:
if reaction.emoji == '1️⃣':
check = discord.utils.get(guild.categories, name="Chilly Logs") # Find the Category
if not check: # If category doesnt exist create the logs
cat = await channel.guild.create_category_channel('Chilly Logs')
await channel.guild.create_text_channel("Message Logs", category=cat) # Message Logs
await channel.guild.create_text_channel("Other Logs", category=cat) # Other Logs
await channel.send('**Log Channels Were Succesfully Added!**')
await message.remove_reaction('1️⃣', user)
return
else:
await channel.send('**Log Channel Already Exists**')
await message.remove_reaction('1️⃣', user)
if reaction.emoji == '2️⃣':
channel1 = discord.utils.get(guild.channels, name="other-logs") # Other Logs
channel2 = discord.utils.get(guild.channels, name="message-logs") # Message Logs
category = discord.utils.get(guild.categories, name="Chilly Logs") # Category/Parent
if category is not None: # Deletes All The Channels
await channel1.delete()
await channel2.delete()
await category.delete()
await channel.send('**Logging Channels Have Been Removed**')
await message.remove_reaction('2️⃣', user)
else:
await channel.send('**Channels Either Dont Exist Or Have Been Renamed**')
await message.remove_reaction('2️⃣', user)
if reaction.emoji == '❗':
#commands.command()
async def test(self, ctx):
embed = discord.Embed(title = "Chilly Logging", description = "Chilly Will Log Any Edited, Deleted Messages. More Features & Flexibility Coming Soon", colour = discord.Color.blurple())
embed.add_field(name="Logging Commands ", value="1️⃣ - Turn On Server Logging", inline=True)
embed.add_field(name=" ", value= "2️⃣ - Delete & Turn Off Logging", inline=False)
msg = await ctx.send(embed=embed)
emoji = ['1️⃣', '2️⃣', '❗']
response = 3
for i in range(response):
await msg.add_reaction(emoji[i])
#commands.Cog.listener()
async def on_message_delete(self, message):
if x == True:
if not message.author.bot: # Checks for bot message
channel = message.channel.name # Channel the deleted message is from
logchannel = discord.utils.get(message.guild.channels, name='message-logs') # Finds the log channel
embed = discord.Embed(title="Message Log", description="", color= discord.Color.red()) # Embeds
embed.add_field(name="Message sent by {} has been deleted in `{}`" .format(message.author.display_name, channel), value=message.content, inline=True,)
embed.set_footer(text='User ID: {} | Message ID: {}' .format(message.author.id, message.id))
await logchannel.send(embed=embed) # Finally sends the embed to log channel
#commands.Cog.listener()
async def on_message_edit(self, before, after):
if not after.author.bot:
if before.content != after.content:
channel = after.channel.name # Channel the edited message is from
logchannel = discord.utils.get(after.guild.channels, name='message-logs') # Finds the log channel
embed = discord.Embed(title="Message Log", description="Message edited in `{}` by {}" .format(channel, after.author.display_name), color= discord.Color.red()) # Embeds
embed.add_field(name="Before", value=before.content, inline=True,)
embed.add_field(name="After", value=after.content, inline=False,)
embed.set_footer(text='User ID: {} | Message ID: {}' .format(after.author.id, before.id))
await logchannel.send(embed=embed) # Finally sends the embed to log channel
def setup(bot):
bot.add_cog(log(bot))```
You could use a global variable. Simply:
Toggle = True
#bot.command()
async def toggle(ctx):
global Toggle
# Toggles the variable.
Toggle = !Toggle
# Example event
#bot.event
async def on_message(message):
if Toggle:
# Event's code
else:
await message.channel.send("Function disabled")
I have created a bot that will lock every channel when I type the command, however, I don't want it to lock the staff ones and the announcement ones.
Here is my code so far:
#bot.command(aliases=['r'])
#commands.has_permissions(manage_channels=True)
async def lockdown(ctx):
for guild in bot.guilds:
for channel in guild.text_channels:
channel = channel
overwrite = channel.overwrites_for(ctx.guild.default_role)
overwrite.send_messages = False
await channel.set_permissions(ctx.guild.default_role, overwrite=overwrite)
await channel.send('Lockdown has started')
How can I do this?
You can exclude channels which you dont want to lock by name using a blocking statement. Like this:
#bot.command(aliases=['r'])
#commands.has_permissions(manage_channels=True)
async def lockdown(ctx):
for guild in bot.guilds:
for channel in guild.text_channels:
if channel.name in ['dont_lock_ch_name_1', 'dont_lock_ch_name_2']:
continue
overwrite = channel.overwrites_for(ctx.guild.default_role)
overwrite.send_messages = False
await channel.set_permissions(ctx.guild.default_role, overwrite=overwrite)
await channel.send('Lockdown has started')
I want that when someone reacts to one emoji the bot writes as a log on chat like this:
#Santa has press 4️⃣
I tried to make it but I'm stuck.
import discord
import time
import random
from discord.ext import commands
client = discord.Client()
bot = client.user
if message.content.startswith('ººrandgame'):
original = await message.channel.send('Discover the number I my mind...')
uno = await original.add_reaction('1️⃣')
dos = await original.add_reaction('2️⃣')
tres = await original.add_reaction('3️⃣')
cuatro = await original.add_reaction('4️⃣')
cinco = await original.add_reaction('5️⃣')
seis = await original.add_reaction('6️⃣')
siete = await original.add_reaction('7️⃣')
ocho = await original.add_reaction('8️⃣')
nueve = await original.add_reaction('9️⃣')
diez = await original.add_reaction('🔟')
numbers = ['1️⃣','2️⃣','3️⃣','4️⃣','5️⃣','6️⃣','7️⃣','8️⃣','9️⃣','🔟']
#this part fails::
if(reaction.emoji == "1️⃣"):
await message.channel.send(author + "has press 1️⃣")
#the same idea with the other numbers
time.sleep(15)
finalnum = random.choice(numbers)
await message.channel.send('My number is: ' + finalnum)
print(finalnum)
client.run('blabla')
You can use a reaction_wait_for, this will always wait for the author of the message input of the specified reaction.
Below I've made a simple user reaction command but I'll leave it up to you how you would further like to improve it.
message = await ctx.send("React to a number")
one = '1️⃣'
two = '2️⃣'
await message.add_reaction(one)
await message.add_reaction(two)
def check(reaction, user):
return user == ctx.author and str(reaction.emoji) in [one, two]
member = ctx.author
while True:
try:
reaction, user = await client.wait_for("reaction_add", timeout=600.0, check=check)
if str(reaction.emoji) == one:
await ctx.send("You choose 1")
if str(reaction.emoji) == two:
await ctx.send("You choose 2")
In your code, I would also reccomend using asyncio.sleep(15) instead of time.sleep, as this causes the whole bot to stop, meaning no one can use it at all.
Make sure to import asyncio
You can also set it as a command, instead of using if message.content.startswith('ººrandgame'): , You can use
#client.command()
async def ººrandgame(ctx):
.... Rest of your code ...
Ibidem, I think that something is missing
import discord
import os
import random
import asyncio
from discord.ext import commands
client = discord.Client()
horaact = time.strftime('%H:%M:%S')
os.system('cls')
os.system('color 1f')
#client.event
async def on_ready():
print("Encendido")
print("logged in as {0.user}".format(client))
#client.command()
async def ººrandgame(ctx):
message = await ctx.send("React to a number")
one = '1️⃣'
two = '2️⃣'
await message.add_reaction(one)
await message.add_reaction(two)
def check(reaction, user):
return user == ctx.author and str(reaction.emoji) in [one, two]
member = ctx.author
while True:
try:
reaction, user = await client.wait_for("reaction_add", timeout=600.0, check=check)
if str(reaction.emoji) == one:
await ctx.send("You choose 1")
if str(reaction.emoji) == two:
await ctx.send("You choose 2")
client.run('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
Remember, this is not the original code, it's just a test for trying your funtion
I have the following code to generate embed from a message , it works fine now what I want is after creating embed the bot should ask the user to mention a channel and after the user mentions a channel , the bot should send that embed there. How do I do it?
#bot.command()
async def embed(ctx):
await ctx.send("Enter title for embed:")
e = await get_input_of_type(str, ctx)
await ctx.send("Enter the content for embed:")
c = await get_input_of_type(str, ctx)
embed = discord.Embed(
title = e,
description = c,
color = 0x03f8fc,
timestamp= ctx.message.created_at
)
embed.set_thumbnail(url = ctx.guild.icon_url)
await ctx.channel.send(embed=embed)
Using wait_for() and TextChannelConverter
#bot.command()
async def embed(ctx):
def check(m):
return m.author == ctx.author and m.channel == ctx.channel
await ctx.send("Enter title for embed:")
e = await get_input_of_type(str, ctx)
await ctx.send("Enter the content for embed:")
c = await get_input_of_type(str, ctx)
embed = discord.Embed(
title = e,
description = c,
color = 0x03f8fc,
timestamp= ctx.message.created_at
)
embed.set_thumbnail(url = ctx.guild.icon_url)
channel = await bot.wait_for("message", check=check)
channel = await commands.TextChannelConverter().convert(ctx, channel.content)
await channel.send(embed=embed)
I used the Client.wait_for() coroutine to wait for a message from the user. Then I formatted the message.content string to get just the ID of the channel. Then I used the discord.utils.get method to get the channel using just the ID.
# at the top of the file
from discord.utils import get
#client.command()
async def embed(ctx):
# embed stuff here
def check(msg):
# make sure the author of the message we're waiting for is the same user that invoked the command
return ctx.author == msg.author
await ctx.send("mention a channel to send to")
msg = await client.wait_for('message', timeout=60.0, check=check)
msg = msg.content.split("#")[1].split('>')[0]
"""
over here we are spliting the '#' from the message content first and index just the ID with the '>'
(if the message is just a channel mention it shoud be something like this: <#000000000000000000>)
then we split the '>' from the string and index just the ID part and now we have the ID of the channel
"""
channel = get(ctx.guild.channels, id=int(msg))
await channel.send(f'{words}')
I have a background loop that will spit out an emoji every X amount of minutes with a reaction attached to it. I want for when someone presses on the reaction of the message, it will delete the message and then send another message saying "messageauthor has grabbed the loot" and then add the amount to the cash json file.
Right now, my code is making the background loop work, but I am not sure how to grab the message.author.id in regards to the background loop so I can reference it in on_reaction_add. The current code is making the bot react once when it spits out the background loop and then again in on_reaction_add. I'm trying to make it wait for a user to react to the background loop message with the same emoji and not the bot.
client = discord.Client()
emoji_msg_grab = {}
try:
with open("cash.json") as fp:
cash = json.load(fp)
except Exception:
cash = {}
def save_cash():
with open("cash.json", "w+") as fp:
json.dump(cash, fp, sort_keys=True, indent=4)
def add_dollars(user: discord.User, dollars: int):
id = user.id
if id not in cash:
cash[id] = {}
cash[id]["dollars"] = cash[id].get("dollars", 0) + dollars
print("{} now has {} dollars".format(user.name, cash[id]["dollars"]))
save_cash()
async def background_loop():
await client.wait_until_ready()
while not client.is_closed:
channel = client.get_channel("479919577279758340")
emojigrab = '💰'
emojimsgid = await client.send_message(channel, emojigrab)
await client.add_reaction(emojimsgid, "💵")
user_id = emojimsgid.author.id
emoji_msg_grab[user_id] = {"emoji_msg_id": emojimsgid.id, "emoji_user_id": user_id}
await asyncio.sleep(600)
#client.event
async def on_reaction_add(reaction, user):
msgid = reaction.message.id
chat = reaction.message.channel
if reaction.emoji == "💵" and msgid == emoji_msg_grab[user.id]["emoji_msg_id"] and user.id == emoji_msg_grab[user.id]["emoji_user_id"]:
emoji_msg_grab[user.id]["emoji_msg_id"] = None
await client.send_message(chat, "{} has grabbed the loot!".format(user.mention))
await client.delete_message(reaction.message)
add_dollars(user, 250)
client.loop.create_task(background_loop())
I would use Client.wait_for_reaction instead of on_reaction_add:
async def background_loop():
await client.wait_until_ready()
channel = client.get_channel("479919577279758340")
while not client.is_closed:
emojigrab = '💰'
emojimsg = await client.send_message(channel, emojigrab)
await client.add_reaction(emojimsg, "💵")
res = await client.wait_for_reaction(emoji="💵", message=emojimsg, timeout=600,
check=lambda reaction, user: user != client.user)
if res: # not None
await client.delete_message(emojimsg)
await client.send_message(channel, "{} has grabbed the loot!".format(res.user.mention))
await asyncio.sleep(1)
add_dollars(res.user, 250)