main.py:
import asyncio
import discord
from event import Event
from discord.ext import commands
import sqlite3
import os
TOKEN = 'token lol'
bot = commands.Bot(command_prefix='+', intents=discord.Intents.all())
bot.add_cog(Event(bot))
bot.run(TOKEN)
event.py:
import asyncio
import discord
from discord.ext import commands
import sqlite3
class Event(commands.Cog):
def __init__(self, bot):
self.bot = bot
#commands.Cog.listener()
async def on_ready(self):
db = sqlite3.connect("eco.sqlite")
cursor = db.cursor()
cursor.execute(f"CREATE TABLE IF NOT EXISTS eco (usr_id INTERGER, usr_sp INTERGER)")
print("bot ready")
#commands.Cog.listener()
async def on_message(self, message):
if message.author.bot:
return
author = message.author
db = sqlite3.connect("eco.sqlite")
cursor = db.cursor()
cursor.execute(f"SELECT usr_id FROM eco WHERE usr_id = {author.id}")
result = cursor.fetchone()
if result is None:
sql = (f"INSERT INTO eco (usr_id, usr_sp) VALUES (?, ?)")
val = (author.id, 750)
cursor.execute(sql, val)
db.commit()
cursor.close()
db.close()
output:
e:\DiscordBot\Bot\main.py:11: RuntimeWarning: coroutine 'BotBase.add_cog' was never awaited
bot.add_cog(Event(bot))
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
2023-02-16 19:00:45 INFO discord.client logging in using static token
2023-02-16 19:00:46 INFO discord.gateway Shard ID None has connected to Gateway (Session ID: 87bb94ab78d04363a6b25ccb433e5993).
I tried to look for a solution to this and found nothing
someone help me pls
The error basically tells you what you need to do. bot.add_cog is now a coroutine function which you need await keyword for calling it.
Also, consider switching the add_cog method's location into your event.py:
# under your event.py, outside of class
async def setup(bot):
await bot.add_cog(Event(bot))
This would be a cleaner way to rewrite.
Related
import os
import discord
import requests
import time
import datetime
class MyClient(discord.Client):
async def on_ready(self):
await client.change_presence(activity=discord.Activity(type=0, name='HIDDENSTATUS'))
print('Logged on as {0}!'.format(self.user))
async def on_message(self, message):
msglower = message.content.lower()
channelStatusSV = client.get_channel(HIDDENCHANNELID)
if msglower == '!refresh':
standard = formated_info('HIDDENIP', '36963', 'ok')
messageStandard = await channelStatusSV.fetch_message(HIDDENMESSAGEID)
await messageStandard.edit(content=standard)
client = MyClient()
client.run('HIDDENTOKEN')
This is the full script (with some hidden info like IP, URL, etc).
It fetches my game server info into an embedded bot message. Currently, it fetches info on demand.
How can I change it to automatically fetch every minute?
Assuming that you're using discord.py; you can use tasks! Have it loop on the interval you want, query the server, and update the message.
I'm developing discord bot with discord.py==2.1.0.
I use cog to write the main function that I wanna use, but I found when the whole bot is wrapped in async function and called by asyncio.run(), my terminal won't show any error message when there is any runtime error in my cog script.
Here is the example application. I stored my bot token in environment variable.
bot.py
import os
import discord
from discord.ext import commands
import asyncio
token = os.environ["BOT_TOKEN"]
class Bot(commands.Bot):
def __init__(self):
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
description = "bot example."
super().__init__(
command_prefix=commands.when_mentioned_or('!'),
intents=intents,
description=description
)
async def on_ready(self):
print(f'Logged in as {self.user} (ID: {self.user.id})')
print('------')
bot = Bot()
async def load_extensions():
for f in os.listdir("./cogs"):
if f.endswith(".py"):
await bot.load_extension("cogs." + f[:-3])
async def main():
async with bot:
await load_extensions()
await bot.start(token)
asyncio.run(main())
./cogs/my_cog.py
from discord.ext import commands
class Test(commands.Cog):
def __init__(self, client):
self.client = client
#commands.Cog.listener()
async def on_ready(self):
print("Ready")
#commands.command()
async def command(self, ctx):
test_error_message() # An runtime error example
print("Command")
async def setup(client):
await client.add_cog(Test(client))
Command that I run in terminal to start the bot.
python bot.py
When I type !command in the discord channel, there is no error message showing in the terminal, but there is no "Command" printed out so I'm sure the code stopped at the line I called test_error_message()
I expected that it should show error message normally, but I cannot find useful reference to make it work :(
There is one reason I need to use asyncio, I have a task loop to run in the bot, like the code below.
from discord.ext import tasks
#tasks.loop(seconds=10)
async def avatar_update():
# code here
async def main():
async with bot:
avatar_update.start()
await load_extensions()
await bot.start(token)
I would happy to know if there are some great practice to handle error in this situation.
Thanks!
Client.start() doesn't configure logging, so if you want to use that then you have to do it yourself (there's setup_logging to add a basic config). run() configures logging for you.
For more info, read the docs. https://discordpy.readthedocs.io/en/stable/logging.html?highlight=logging
I'm trying to record twitch chat messages while still recognizing commands, however, recording the messages using event_message seems to stop the command from working.
Anybody know how you would recognize/respond to commands and record message at the same time?
from twitchio.ext import commands
import time
from datetime import datetime
class Bot(commands.Bot):
def __init__(self):
super().__init__(
token='oauth:',
prefix='!',
initial_channels=['channelname']
)
# This function isn't running; event_message is stealing the input!
#commands.command(name='ping')
async def my_command(self, ctx):
print('Caught ping')
await ctx.send('pong')
# records the messages (or in this case, the time a message is sent)
async def event_message(self, message):
print(time.mktime(datetime.now().timetuple())) # prints the unix second
if __name__ == '__main__':
bot = Bot()
bot.run()
Reducing this down even more, the same issue occurs here; with the bot responding to the command, but not printing the message author or content:
from twitchio.ext import commands
import os
bot = commands.Bot(
token='', prefix="!", initial_channels=[""], client_id='', nick='', client_secret='')
#This isn't working; Should still grab the message author/name and print.
Ive tried twitchio versions between 1.3.0 and 2.3.0, but the issue persists.
#bot.event
async def event_message(ctx):
print(ctx.author.name)
print(ctx.content)
await bot.handle_commands(ctx)
#This is running
#bot.command(name='test')
async def test_command(ctx):
await ctx.send('this is a test response')
if __name__ == '__main__':
bot.run()
Issue was not including an "await bot.handle_commands(ctx)" command below the event_message function.
Attached below is a working code
from twitchio.ext import commands
class Bot(commands.Bot):
def __init__(self):
super().__init__(token='', prefix="!", initial_channels=[""])
#commands.command()
async def ping(self, ctx):
print('Caught Ping')
await ctx.send(f'Pong!')
async def event_message(self, message):
print(message.author.name, message.content)
await bot.handle_commands(message) # <--This is the new line
bot = Bot()
bot.run()
NOTE: An error is raised by the event_message function when the bot sees one of its' own messages in chat. This doesn't seem to inhibit function, but it can be fixed by changing the code to the following:
async def event_message(self, message):
if hasattr(message.author, 'name'): # <-- New Line
print(message.author.name, message.content)
await bot.handle_commands(message)
I'm trying to use a listener event to activate a function I have in a cog using discord.py. This same code functions properly in the main bot.py file (removing self and using #client.event instead of a listener) but when used in the cog, it tells me that the repeater() function is an undefined variable when being used in the listener event
import discord
from discord.ext import commands, tasks
class Repeater(commands.Cog):
def __init__(self, client):
self.client = client
#tasks.loop(seconds = 10)
async def repeater(self):
channel = self.client.get_channel(834554679265329172)
await channel.send('test')
#commands.Cog.listener()
async def on_ready(self):
repeater.start()
def setup(client):
client.add_cog(Repeater(client))
EDIT:
So I changed the code match this after a comment recommended it, and the console throws this error
#commands.Cog.listener()
async def on_ready(self):
self.repeater()
> discord.ext.commands.errors.ExtensionFailed: Extension 'cogs.repeater'
> raised an error: TypeError: Cog.listener expected str but received
> 'function' instead.
EDIT 2:
Changed the code to match this, and it will run the loop exactly one time, but doesn't actually loop
#commands.Cog.listener()
async def on_ready(self):
await self.repeater()
In class you have to use self. to access its method self.repeater and self.repeater.start()
I tested it on this code and it works for me.
import discord
from discord.ext import commands, tasks
import os
import datetime
TOKEN = os.getenv('DISCORD_TOKEN')
CHANNEL = 834554679265329172
class Repeater(commands.Cog):
def __init__(self, client):
self.client = client
#tasks.loop(seconds=10)
async def repeater(self):
#channel = self.client.get_channel(CHANNEL)
await self.channel.send(datetime.datetime.now().strftime("It's %H:%M.%S"))
#commands.Cog.listener()
async def on_ready(self):
self.channel = self.client.get_channel(CHANNEL)
print('starting repeater')
self.repeater.start()
def setup(client):
client.add_cog(Repeater(client))
# --- main ---
client = commands.Bot(command_prefix='!')
setup(client)
print('starting bot')
client.run(TOKEN)
repeater is a function of the class. So you can call it with self.repeater. And to start a discord task use start attribute. self.repeater.start() is the answer.
I am trying to make the bot leave a server with the ID, Command !leave
I get the error 'Bot' object has no attribute 'get_server'
Here is my script:
import discord
from discord.ext import commands
client = commands.Bot(command_prefix='!')
token = TOKEN HERE
#client.command()
async def leave(ctx, ID):
toleave = client.get_server(ID)
await client.leave_server(toleave)
print("Left Server")
client.run(token)
Since, discord.py 1.1, get_server has been renamed to get_guild, and leave_server has been moved to Guild.leave. So, your code would look something like:
toleave = client.get_guild(ID)
await toleave.leave()
This should work
#commands.command()
async def leave(self, ctx, *, message=None ):
guild_id = message
guild = await self.client.get_guild(int(guild_id))
channel = guild.system_channel
await channel.send("Leaving this server due to misuse!")
await guild.leave()