Make bot automatically quit after it has done its work - python

I'd like to use my bot not as a daemon that runs forever, but as a kind of "shell script". So it should automatically quit after it has done its work.
My approach so far in Python 3.5 / Python 3.6:
import discord
TOKEN = '<redacted>'
client = discord.Client()
#client.event
async def on_ready():
for member in client.get_all_members():
print(member.display_name)
# please, please quit now!
client.run(TOKEN)
What I want here is, that the script should just quit after printing all the members' display_names, so I can further process them elsewhere. At the moment it DOES print the desired information, but continues to run forever.

Answering my question myself:
Just replace the line # please, please quit now! with await client.logout() does the job.

Related

Displaying Cooldown In Seconds in On_Message in Discord.py

EDIT:
I solved it, I just simply looped the asyncio.sleep and set a variable for the cooldown in seconds. :)
I'm new to discord.py and I just started developing a bot.
Most bots like Dank Memer has cooldowns after the on_message events happens. (I don't know if Dank Memer is in discord.py or not)
So I want to do the same, but I do not know how to display the cooldown in seconds. (Before you can enter another on_message event)
This is part of my code so far: (This is the cooldown)
import discord,asyncio #and some other modules
cooldown = []
async def on_message(message):
# Some Code
cooldown.append(message.author.id)
await asyncio.sleep(60)
cooldown.remove(message.author.id)
This code works, it doesn't show how many seconds you have before you can enter another command again.
My code is actually pretty long, so I don't want to rewrite it.
Is there a way to display how many seconds you have got left if the user enters the same command within the cooldown?
Ok, I solve it myself.
At the start you do:
cooldown = []
cooldownSec = 60 # How many seconds
cooldowntime = 0
Then, after the events from the on_message:
cooldown.append(message.author.id)
for i in range(cooldownSec,-1,-1):
if i == 0:
cooldown.remove(message.author.id)
break
cooldowntime = i
asyncio.sleep(1)
Put this line of code at the start of the on_message function:
global cooldowntime
Then, at the start of a message event happens:
if message.content.lower().startswith('!test'):
if message.author.id in cooldown:
await message.reply(f'You have to wait for {cooldowntime} more seconds before you can use the commands again!')
It should work.

Discord.py Bot send messages at certain times

I host a discord.py bot on a server for me and some friends, and have been trying to get a certain 'feature', where the bot will send a message every day, twice daily, once in the morning, once in the night, just saying general "good morning" and "good night!" I have spent hours looking through other peoples codes, and similar questions, and this is the best I can find/have gotten (It's taken from another user's 'python alarm', and I tried to hook it up to the bot.
from datetime import datetime
from threading import Timer
x = datetime.today()
y = x.replace(hour=21, minute=45, second=40, microsecond=0)
delta_t = y - x
secs = delta_t.seconds + 1
channel = client.get_channel(806702411808768023)
async def Goodnight():
await channel.send("Good night! Make sure to go to sleep early, and get enough sleep!")
print("Night Working")
t = Timer(secs, Goodnight)
t.start()
I keep getting the same error(s), usually about the message not being async or await-'able' (?). I am fairly new to coding/python, sorry if anything is obvious. I really do not know what to do, and I have found some promising solutions, though those make the whole bot the alarm, and force it to 'sleep' while waiting, while I want mine to still function normally (run other commands), if possible? Any help appreciated
This can be done using the tasks extension:
import datetime
import discord
from discord.ext import tasks
client = discord.Client()
goodNightTime = datetime.time(hour=21, minute=45, second=40) #Create the time on which the task should always run
#tasks.loop(time=goodNightTime) #Create the task
async def Goodnight():
channel = client.get_channel(806702411808768023)
await channel.send("Good night! Make sure to go to sleep early, and get enough sleep!")
print("Night Working")
#client.event
async def on_ready():
if not Goodnight.is_running():
Goodnight.start() #If the task is not already running, start it.
print("Good night task started")
client.run(TOKEN)
Note that for that to work you need to have the latest version of either discord.py or a fork which supports version 2.0. If you don't have it yet, you can install it via
pip install -U git+https://github.com/Rapptz/discord.py

TwitchIO bot without blocking

I'd like to use TwitchIO to talk to Twitch chat inside another program, without needing to hijack the main loop with Bot's run().
The official documentation here (https://twitchio.readthedocs.io/en/latest/quickstart.html) shows the code being run like:
from twitchio.ext import commands
class Bot(commands.Bot):
def __init__(self):
# Initialise our Bot with our access token, prefix and a list of channels to join on boot...
# prefix can be a callable, which returns a list of strings or a string...
# initial_channels can also be a callable which returns a list of strings...
super().__init__(token='ACCESS_TOKEN', prefix='?', initial_channels=['...'])
async def event_ready(self):
# Notify us when everything is ready!
# We are logged in and ready to chat and use commands...
print(f'Logged in as | {self.nick}')
#commands.command()
async def hello(self, ctx: commands.Context):
# Here we have a command hello, we can invoke our command with our prefix and command name
# e.g ?hello
# We can also give our commands aliases (different names) to invoke with.
# Send a hello back!
# Sending a reply back to the channel is easy... Below is an example.
await ctx.send(f'Hello {ctx.author.name}!')
bot = Bot()
bot.run()
# bot.run() is blocking and will stop execution of any below code here until stopped or closed.
But as that last line says, run() will block execution.
Is there some other way of running it that doesn't block? Something like (made up)
bot.poll()
That would need to be run periodically in my program's main loop?
Are you adding any more code that uses the Bot class? If not I would suggest just making 2 processes.
The simplest way to do this is just creating 2 python files and running both of them at the same time.
If you really must run them both on the same program I would look into parallel processing. The next time you post a question I would suggest putting that "other programs" code into the question so people don't have to make those assumptions.
#ps if you need to run them in the same program edit your question to show the code you need to run together and ill take another look

Running multiple commands with discord.py

Using discord.py and python:
Ok so basically I have this bot that updates the best prices for a certain game every minute. However, while I am doing that, other people cannot access the bot. For example, lets just say I have a command called "hello" that when called prints hello out in the chat. Since the code always runs, the user cant call the command hello because the code is too busy running the code that updates every minute. Is there any way to like make it so that the updateminute code runs while others can input commands as well?
import discord
import asyncio
import bazaar
from discord.ext import commands, tasks
client = commands.Bot(command_prefix = '.')
#client.command()
async def calculate(ctx):
while True:
await ctx.send(file2.calculate())
await asyncio.sleep(210)
#client.command()
async def hello(ctx):
await ctx.send("Hello")
client.run(token)
In file2.py:
def updateminute():
for product in product_list:
#Grab Api and stuff
#check to see whether it is profitable
time.sleep(0.3) #cause if i don't i will get a key error
#calculate the stuff
#return the result
To sum up, since the bot is too busy calculating updateminute and waiting, other people cannot access the bot. Is there any way I can try to fix this so that the bot calculates its stuff and so people can use the bots commands? Thanks!
You can look into threading! Basically, run two separate threads: one for taking requests and one for updating the prices.
You could also look into turning it into an async function, essentially making it easier to run things concurrently.
So your standard def will become async def and then to call the function you simply add an await before it so await file2.calculate()
Hope it helps and is also somewhat easier to understand

on_reaction_add not being run

I'm new to discord.py and trying to make a translator bot. When the user reacts with a certain flag, the bot translates it, but the event is never getting called hence I have no code to translate any messages yet. I know it's not getting called because the program isn't printing an 'x' to the console.
#client.event
async def on_reaction_add(reaction, user):
channel = reaction.message.channel
print('x')
await client.send_message(channel, '{} has added {} to the the message {}'.format(user.name, reaction.emoji, reaction.message.content))
await client.process_commands(reaction.message)
Probably a bit late to this thread but, the answer above is a valid answer. But you can also use on_raw_reaction_add which gets called even if the messages aren't in the Bot's cache.
Called when a message has a reaction added. Unlike on_reaction_add(), this is called regardless of the state of the internal message cache.
Documentation Link
Example:
#commands.Cog.listener()
async def on_raw_reaction_add(self, payload):
channel = await self.bot.fetch_channel(payload.channel_id)
message = await channel.fetch_message(payload.message_id)
user = await self.bot.fetch_user(payload.user_id)
emoji = payload.emoji
await channel.send("Hello")
There isn't much valid reason for why the event isn't registered/called.
One of which is stated in the docs: http://discordpy.readthedocs.io/en/async/api.html#discord.on_reaction_add. Try adding a reaction immediately to a message that is sent after the bot is online. Since messages sent before the bot is online will not be recognized by the bot (not in Client.messages).
if the message is not found in the Client.messages cache, then this
event will not be called.
Another possible reason is that this function was never defined before the client loop commenced. Verify your indentation. And/Or try placing the function directly under client = Bot(...), to check if this is the problem.
If neither of the aforementioned solves your problem, please post a minimal, complete, verifiable example (a short runnable code from top to bottom that indicates your problem).

Categories