Can't make a discord bot send a message inside a python function
I would like to create a discord bot that sends a message in a specific channel, when a twitter account follows a new account.
I managed to work with the twitter API, but i cant make the part where it sends the message on discord, it's just a string to send in a function
I keep seeing discord bots that reacts to commands typed in a channel, but i want to have a bot that sends message by himself and not wait for a command.
i don't really understand the async things (https://github.com/Rapptz/discord.py/blob/master/examples/background_task.py) i couldnt figure it out by myself can someone try to help me please
def sendDiscordMessage(friendUser, eachUserToScrape):
friendUserScreenName = friendUser.screen_name
friendUserDescription = friendUser.description
friendUserFollowersCount = str(friendUser.followers_count)
client = discord.Client()
discordMessage = "\n\n=======================================================\n\n" + "👀** User @" + eachUserToScrape + " started following : @" + friendUserScreenName + " 👀**\n\nLink profile : https://twitter.com/" + friendUserScreenName + "\n\nSubscribers count : "+ friendUserFollowersCount + "\n\nDescription : " + friendUserDescription
channel = client.get_channel(...)
print(discordMessage + type(discordMessage))
await channel.send(discordMessage)
As @Łukasz Kwieciński said, you'll be getting an 'await' outside async function
error. To check if the code works and let be the screen_name
and description
attributes, I made a class, assuming your whostartedfollowing
and whoisbeingfollowed
are of a class that resembles user
:
class user:
def __init__(self):
self.screen_name = "screen name"
self.description = "description"
self.followers_count = 3
Coming to the actual part of the question: sending a message without await
ing for a command, you can send the message anytime you want. For example, you can send the message when the bot starts using its on_ready()
method, something like this:
@client.event
async def on_ready(): #When the bot starts
print(f"The bot is online and is logged in as {client.user}")
#Do some scraping here and get the actual whostartedfollowing and whoisbeingfollowed (from Twitter).
whostartedfollowing:user = user()
whoisbeingfollowed:user = user()
await sendDiscordMessage(whoisbeingfollowed, whostartedfollowing)
print("sent the message")
in which sendDiscordMessage()
is the function in your code, but a bit modified to reduce errors:
async def sendDiscordMessage(friendUser, eachUserToScrape):
friendUserScreenName = friendUser.screen_name
friendUserDescription = friendUser.description
friendUserFollowersCount = str(friendUser.followers_count)
discordMessage = "\n\n=======================================================\n\n" + "👀** User @" + eachUserToScrape.screen_name + " started following : @" + friendUserScreenName + " 👀**\n\nLink profile : https://twitter.com/" + friendUserScreenName + "\n\nSubscribers count : "+ friendUserFollowersCount + "\n\nDescription : " + friendUserDescription
#Since screen_name is a string, I just used it instead of the object, so it can be joined with the rest as a string.
channel = client.get_channel(...) #Get the channel with its ID (an `int`), for example a channel with
print(channel) #To check if the channel is None or not.
print(discordMessage) #and not "print(discordMessage + type(discordMessage))", or you can use "print(discordMessage + str(type(discordMessage)))"
await channel.send(discordMessage)
You can do the same thing without await
ing, by not making your sendDiscordMessage(friendUser, eachUserToScrape)
function async
(letting it be sendDiscordMessage(friendUser, eachUserToScrape)
and not adding async
to make it async def sendDiscordMessage(friendUser, eachUserToScrape)
), if you don't want to depend on the result of the await
ed coroutine. But, you'll get a RuntimeWarning: coroutine 'Messageable.send' was never awaited
.
If you have to wait for the result of the awaited coroutine, where if the awaited coroutine crashes, then the rest of the code won't work either, or where the order of execution is important, then use await
and change def sendDiscordMessage(friendUser, eachUserToScrape)
to:
async def sendDiscordMessage(friendUser, eachUserToScrape):
Also, you're using discord.Client
and not discord.ext.commands.Bot
. The latter is just an extension of the former, with more features. You may want to switch to commands.Bot
.
Here's the full code:
from discord.ext import commands
client = commands.Bot(command_prefix="")
class user:
def __init__(self):
self.screen_name = "screen name"
self.description = "description"
self.followers_count = 3
@client.event
async def on_ready(): #When the bot starts
print(f"Bot online and logged in as {client.user}")
#Do some scraping here and get the actual whostartedfollowing and whoisbeingfollowed (from Twitter).
whostartedfollowing:user = user()
whoisbeingfollowed:user = user()
await sendDiscordMessage(whoisbeingfollowed, whostartedfollowing)
print("sent the message")
async def sendDiscordMessage(friendUser, eachUserToScrape):
friendUserScreenName = friendUser.screen_name
friendUserDescription = friendUser.description
friendUserFollowersCount = str(friendUser.followers_count)
discordMessage = "\n\n=======================================================\n\n" + "👀** User @" + eachUserToScrape.screen_name + " started following : @" + friendUserScreenName + " 👀**\n\nLink profile : https://twitter.com/" + friendUserScreenName + "\n\nSubscribers count : "+ friendUserFollowersCount + "\n\nDescription : " + friendUserDescription
#Since screen_name is a string, I just used it instead of the object, so it can be joined with the rest as a string.
channel = client.get_channel(...)
print(channel)
print(discordMessage) #and not "print(discordMessage + type(discordMessage))", or you can use "print(discordMessage + str(type(discordMessage)))"
await channel.send(discordMessage)
client.run("token")
Here are some uses of async
-await
.