how to run a command in tasks.loop discord.py bot - python

so im trying to get a command to run every 5 minutes on my dsicrod.py bot and need ctx to get guild members and certain details like that so I need it in a bot.command, but I cant have that properly do that without tasks.loop(minutes=5) so I tried getting it to send the command with tasks.loop but it wouldn't work so I went to the pythin discord and got help they got me to this point
#bot.command(pass_context=True)
async def update_member_count(ctx):
await ctx.send(ctx.guild.member_count)
channel = discord.utils.get(ctx.guild.channels, id=829355122122424330)
await channel.edit(name = f'Member Count: {ctx.guild.member_count}')
#tasks.loop(minutes=5)
async def update_member_count2(ctx):
await update_member_count(ctx)
and It still gives errors saying that ctx arg is missing in update_member_count2. pls help

You can create your loop-function in another way. Your approach is a bit unclear to me.
Try out the following:
async def update_member_count(ctx):
while True:
await ctx.send(ctx.guild.member_count)
channel = discord.utils.get(ctx.guild.channels, id=YourID)
await channel.edit(name=f'Member Count: {ctx.guild.member_count}')
await asyncio.sleep(TimeInSeconds)
#bot.command()
async def updatem(ctx):
bot.loop.create_task(update_member_count(ctx)) # Create loop/task
await ctx.send("Loop started, changed member count.") # Optional
(Or you simply create the task in your on_ready event, depends on you)
What did we do?
Created a loop out of a function (async def update_member_count(ctx):)
Exectued updatem one time to activate the loop
Changed your actual command to a "function"

You could go with #Dominik's answer but its near impossible to stop a running While loop. Going ahead with discord.py tasks.
If you want to start the task with a command:
async def start(ctx):
update_member_count2.start(ctx)
If you want to start it when the bot starts, you have to slightly modify the code
#tasks.loop(minutes=5)
async def update_members():
guild = bot.get_guild(guildID)
channel = guild.get_channel(channelID)
#update channel, don't sleep
# inside init or on_ready
if not update_members.is_running():
update_members.start()

Use this in a on_member_join event
#bot.event
async def on_member_join(member):
channel = discord.utils.get(member.guild.channels, id=962732335386746910)
await channel.edit(name = f'⚫┃・Members: {member.guild.member_count}')

Related

Discord.py: client not working inside tasks?

I am trying to loop a task that would check a member's activity from a certain server every hour, and sending a message on a specific channel if they are still on the same activity. Here is the part of code I need help with:
import discord
from discord.ext import commands, tasks
from keep_alive import keep_alive
intents = discord.Intents.all()
client = commands.Bot(command_prefix="?", intents=intents)
#tasks.loop(seconds = 10, count = 1)
async def checkactiv():
guild = client.get_guild(int(####))
member = guild.get_member(int(####))
channel = client.get_channel(int(####))
if member.activity.name.lower() == "a certain game":
await channel.send("ignore this test message")
checkactiv.start()
I have tried this as a command and it works, but I want it to loop automatically every hour or so (I made it 10 seconds as a test). The error I get is saying that guild and channel are a NoneType, this wasn't the case when I was using as a command like this:
#client.command()
async def test(ctx):
guild = client.get_guild(int(####))
member = guild.get_member(int(####))
await ctx.channel.purge(limit = 1)
if member.activity.name.lower() == "a certain game":
await ctx.send("still playing")
I am not entirely sure what the problem is, but I am assuming that client cannot be called under a task? It obviously works just fine under #client.command, but not within a task loop. Any ideas on how I can fix this? Does it have something to do with my client being commands.Bot rather than discord.Client? I have commands on the Discord bot that is not displayed here so I can't try changing my client.
Any help is appreciated!
client.get_x gets the object from the internal cache, when you start the task the cache is not fully loaded yet, you can use the client.wait_until_ready method to wait till the cache is ready:
#tasks.loop(seconds = 10, count = 1)
async def checkactiv():
guild = client.get_guild(int(####))
member = guild.get_member(int(####))
channel = client.get_channel(int(####))
#checkactiv.before_loop # it's called before the actual task runs
async def before_checkactiv():
await client.wait_until_ready()

How can i show guilds number on status?

im using discord.py and i wanted to showed the number of servers that my bot currently on
it worked but its not updating what should i fix?
I'm writing on Python (in learning) and i've seen this code from the internet
here's my code:
#bot.event
async def on_ready():
activity = discord.Game(name=f"k.cmd for help! | {len(bot.guilds)} Guilds", type=3)
await bot.change_presence(status=discord.Status.idle, activity=activity)
print(f"logged in as {bot.user}")
Do not use a while True: loop like shown in RiveN's answer, that will update the bot's status basically every second which will end up in it getting ratelimited and very laggy.
Use discord.ext.tasks:
from discord.ext import tasks #at the start of your code
#tasks.loop(minutes = 1)
async def change_status():
activity = discord.Game(name=f"k.cmd for help! | {len(bot.guilds)} Guilds", type=3)
await bot.change_presence(status=discord.Status.idle, activity=activity)
#change_status.before_loop
async def before_changing_status():
await bot.wait_until_ready()
change_status.start()
bot.run(your_token_here)
This will update your bot's status every minute, and it will not become laggy while doing so.

How do I make the bot disconnect the voice channel with a command like -disconnect in lavalink.py? {CLOSED FOUND ALTERNATIVE METHOD}

I'm trying to make my discord bot disconnect the voice channel with a command like -disconnect using Lavalink. I have tried doing it in various approaches but it never seems to work for me. I also can't find many examples online. The most recent thing i've tried is this:
#commands.command()
async def leave(self, ctx):
guild_id = int(event.player.guild_id)
await self.connect_to(guild_id, None)
Tell me if you know how to make a disconnect command. Thanks!!!
This is discord.py rewrite btw.
To make a disconnect command is lavalink all you have to do is:
await self.connect_to(ctx.guild.id, None)
Here's an example:
import asyncio
#client.command()
async def disconnect(ctx):
channel = client.get_channel(channelIdHere)
vc = await channel.connect()
await asyncio.sleep(2) # Waits 2 seconds before leaving the vc
await vc.disconnect()
You should check the documentation for more information.

Python Discord.py Bot Interval Message Send

I have been trying to create a bot for Discord using the discord.py library however when I am running the program it is not sending the message as expected. It is a simple bot that is suppose to send a message every 10 minutes to a channel. I am not getting any error messages in the command line and can't seem to see any obvious errors? Any help would be greatly appreciated.
import asyncio
client = discord.Client()
async def my_background_task():
await client.wait_until_ready()
counter = 0
channel = discord.Object(id='my channel ID goes here')
while not client.is_closed:
counter += 1
await message.channel.send("TEST")
await asyncio.sleep(5) # task runs every 60 seconds
#client.event
async def on_ready():
print('Logged in as')
print(client.user.name)
print(client.user.id)
print('------')
client.loop.create_task(my_background_task())
client.run('My token goes here')
Although creating a task could work, I wouldn't recommend it when there are better options. Dpy's command.ext addon has a task based system built in directly, so let's look into using that instead.
import discord
from discord.ext import tasks
client = discord.Client()
#tasks.loop(minutes=10)
async def my_background_task():
"""A background task that gets invoked every 10 minutes."""
channel = client.get_channel(754904403710050375) # Get the channel, the id has to be an int
await channel.send('TEST!')
#my_background_task.before_loop
async def my_background_task_before_loop():
await client.wait_until_ready()
my_background_task.start()
client.run('Your token goes here')
The time until which the above loop will run is dependent upon human psychology, laws of energy and cosmos.
That is:
• You get bored of it
• The power goes down and your script stops working
• The universe explodes
Read more about it here:
https://discordpy.readthedocs.io/en/latest/ext/tasks/
If the channel ID is a string, It should be an integer.
Turn this:
channel = discord.Object(id='my channel ID goes here')
into:
channel = discord.Object(id=101029321892839) # an example ID
If that doesn't solve your problem, try setting 'message.channel.send' to 'channel.send' and client.is_closed should be
client.is_closed() # put brackets
Instead of client.loop.create_task(my_background_task()), just put the background function in the on_ready event. And take out await client.wait_until_ready() and just put the function in the on_ready event as well.
I have also changed the client variable, taken out unnecessary code, and added some modules.
import asyncio, discord
from discord.ext import commands
client = commands.Bot(command_prefix = ".") # If you don't want a prefix just take out the parameter.
async def my_background_task():
channel = discord.Object(id='my channel ID goes here')
while True:
await channel.send("TEST")
await asyncio.sleep(5) # task runs every 60 seconds
#client.event
async def on_ready():
print('Logged in as')
print(client.user.name)
print(client.user.id)
print('------')
my_background_task()
client.run('My token goes here')
Also in future when posting a question, please tag the python version as I don't know which version it is and then this and other answers could be wrong.

Allow Discord Rewrite bot to respond to other bots

I have a Discord bot and a webhook setup for a Discord channel to send a command every hour on the dot. However it seems that Discord Rewrite by default ignores commands sent from other bots. How do I go about disabling this?
Do I need to modify something on a per-command function or the on_message function?
Current on_message:
#bot.event
async def on_message(message):
await bot.process_commands(message)
Try adding a check for it:
on_message:
if message.author.bot == True:
#Do something
command:
if ctx.author.bot == True:
#Do something
The solution is:
#bot.event
async def on_message(message):
ctx = await bot.get_context(message)
await bot.invoke(ctx)
as per OP #Cynthia Valdez's edit to the question.

Categories