I made a slash command that echoes a message. But I wanted to separate it from the main.py, and I couldn't do it. I made many commands to cogs before, but none was a Slash Command.
I used the #client.command under:
class echo(commands.Cog):
def __init__(self, client):
self.client = client
#client.command
#the rest of the code
...
I got an error message saying, "interactions.option isn't recognized". I created 3 options (1 required and the rest are optional):
#client.command(name="echo",description="testing", default_member_permissions=interactions.Permissions.ADMINISTRATOR,
options=[
interactions.Option(
name = "text",
required = True,
description = "text",
type = interactions.OptionType.STRING
),
interactions.Option(
name = "channel",
required = False,
description = "channel",
type = interactions.OptionType.CHANNEL
),
interactions.Option(
name = "timer",
required = False,
description = "timer in minutes(e.g. 20, 120)",
type = interactions.OptionType.INTEGER
)])
I've tried finding an alternative, but couldn't make it.
Also, I had an error saying that there was something about ADMINISTRATOR so I made it lowercase. all of these and more work just fine on my main bot file.
here is my whole code in the main file:
import discord, asyncio, interactions
intents = discord.Intents.all()
client = interactions.Client(token="MY TOKEN")
#client.event
async def on_ready():
print("\nBot is awake!\n")
#client.command(name="echo",description="testing", default_member_permissions=interactions.Permissions.ADMINISTRATOR,
options=[
interactions.Option(
name = "text",
required = True,
description = "text",
type = interactions.OptionType.STRING
),
interactions.Option(
name = "channel",
required = False,
description = "channel",
type = interactions.OptionType.CHANNEL
),
interactions.Option(
name = "timer",
required = False,
description = "timer in minutes(e.g. 20, 120)",
type = interactions.OptionType.INTEGER
)])
async def echo(ctx: interactions.CommandContext, text: str, channel: str = None, timer: int = None):
if channel is None and timer is None:
await ctx.send(text)
elif channel is not None and timer is None:
await channel.send(text)
await ctx.send(f"I sent your message to {channel.mention}")
elif channel is None and timer is not None:
await ctx.send(f"I will send your message after {timer} minutes.")
await asyncio.sleep(timer * 60)
await ctx.send(text)
elif channel is not None and timer is not None:
await ctx.send(f"I will send your message in {channel.mention} after {timer}")
await asyncio.sleep(timer * 60)
await channel.send(text)
client.start()
Related
I wrote the code for the output in the error console via utils.setup_logging
Errors were derived correctly when I only used this code:
discord.utils.setup_logging(level = logging.ERROR, root = False)
discord.utils.setup_logging(level = logging.WARN, root = False)
discord.utils.setup_logging(level = logging.WARNING, root = False)
discord.utils.setup_logging(level = logging.INFO, root = False)
All errors displayed such as code synthesis, warning etc.
But today I create a new team and I made a mistake in the code. After checking it, the console would have to derive a mistake, but she did not do it (the team was not fulfilled by itself). I do not know, maybe I really made a mistake in writing the code. But still the console would have to bring out at least some mistake.
# -*- coding: utf-8 -*-
import discord
from discord.ext import commands
from config import settings
import asyncio
import os
import logging
from time import strftime
from time import gmtime
import sqlite3
bot = commands.Bot(settings['prefix'], intents = discord.Intents.all())
bot.remove_command('help')
discord.utils.setup_logging(level = logging.ERROR, root = False)
discord.utils.setup_logging(level = logging.WARN, root = False)
discord.utils.setup_logging(level = logging.WARNING, root = False)
discord.utils.setup_logging(level = logging.INFO, root = False)
#bot.event
async def on_ready():
print(f'{bot.user.name} підключився до Discord.')
async def load_extensions():
"""Load cogs for main file
"""
for filename in os.listdir('./cogs'):
if filename.endswith('.py'):
await bot.load_extension(f'cogs.{filename[:-3]}')
async def main():
await load_extensions()
await bot.start(settings['token'])
if __name__ == '__main__':
asyncio.run(main())
cogs/test.py
class test(commands.Cog, name='Інформативні команди'):
def __init__(self, bot):
self.bot = bot
#commands.command()
async def server(self, ctx):
snsfwlvl = str(ctx.guild.explicit_content_filter)
if snsfwlvl == 'all_members':
snsfwlvl = 'Перевіряти кожного учасника'
elif snsfwlvl == 'no_role':
snsfwlvl = 'Перевіряти учасників без ролей'
elif snsfwlvl == 'disabled':
snsfwlvl = 'Не встановлено'
else:
snsfwlvl = 'Не знайдено'
text_channels = len(ctx.guild.text_channels)
voice_channels = len(ctx.guild.voice_channels)
stage_channels = len(ctx.guild.stage_channels)
total_channels = text_channels + voice_channels + stage_channels
total_members = ctx.guild.members
online = 0
idle = 0
offline = 0
humans = 0
bots = 0
for member in total_members:
if member.status == 'online':
online+=1
if member.status == 'idle':
idle+=1
if member.status == 'oflline':
oflline+=1
if member.bot is True:
bot+=1
if member.bot is False:
humans+=1
embed = discord.Embed(
color = settings['color'],
title = f"Інформація про сервер {ctx.guild.name}"
)
created_at = ctx.guild.created_at
embed.add_field(
name = f"Власник сервера",
value = f"{ctx.guild.owner.mention}",
inline = True
)
embed.add_field(
name = "Id",
value = ctx.guild.id,
inline = True
)
embed.add_field(
name = "Створений: ",
value = strftime("%d.%m.%y %H:%M:%S", created_at),
inline = True
)
embed.add_field(
name = "Перевірка: ",
value = snsfwlvl,
inline = True
)
embed.add_field(
name = "Учасники:",
value = f"<:total_members:1038376493669154836>Всього: **{total_members}**\n<:members:1038376476870979594>Учасників: **{humans}**\n<:bots:1038376472521482263>Ботів: **{bots}**",
inline = True
)
embed.add_field(
name = "Статуси:",
value = f"<:ofline:1038376481774120970>Онлайн: **{online}**\n<:idle:1038376474958381056>Відійшли: **{idle}**\n<:ofline:1038376481774120970>Не в мережі: **{offline}**",
inline = True
)
embed.add_field(
name = "Канали:",
value = f"<:total_channels:1038376491576205375>Всього: **{total_channels}**\n<:text_channels:1038376489399357504>Текстові: **{text_channels}**\n<:voice_channels:1038376495414001724>Голосові: **{voice_channels}**"
)
embed.set_thumbnail(url = ctx.guild.icon)
await ctx.reply(embed=embed)
I've recently updated my code with logging. First of all, after you have imported library, you should give the basic config of your log.
import logging
logging.basicConfig(filename="bot.log", level=logging.INFO, filemode="a")
As you saw there are multiple levels of logs, NOTSET, DEBUG, INFO, WARNING, ERROR and CRITICAL. By stating I want the level=logging.INFO, I actually inform my logging process that I wish to collect only INFO+ levels, so I won't take DEBUG or NOSET.
You can also produce a format for your logs, like :
logging.basicConfig(filename="BotLog.txt", level=logging.INFO, format="%(asctime)s %(message)s", filemode="a")
This will print the time, then the message to log.
What I don't see in your code is the next step, aka calling the log to register an action.
async def register (ctx, name) :
if name == "" :
logging.warning ("| BOT : no name argument !")
else : logging.info ("| BOT : name to register : "+name)
So it is your responsability to setup but also call logging method. Console will produce error message only if your code is wrong at some point, but if your code is fine, there will be no error. Also, you have to call for functions to actually get errors in. If you code for example :
async def returnMessage (ctx) :
ctx.send (ctx.message)
then you'll only get a NoneType error if you call returnMessage message function, because send() is async and needs an await, that interpreter will only consider once in the function.
I have this issue where whenever i do
"/purge 10" i get the error "404 Not Found (error code: 10062): Unknown interaction" and it doesnt send the embed, but for some reason it seems to work whenever i do "/purge 1" and sends the embed
Here's my code:
#commands.hybrid_command(name = "purge", description = "Purges a specified number of messages")
#commands.has_permissions(manage_messages = True)
async def purge(self, ctx : commands.Context, amount : int):
creator = EmbedCreator()
embed = creator.create(
title = "Success",
description = f"```py\nCleared '{amount}' Messages ```",
color = discord.Color.green()
)
await ctx.channel.purge(limit = amount)
await ctx.reply(embed = embed, delete_after = 10, ephemeral = True) # "delete_after" deletes the embed after a certain time
The idea of this command is to send a message in a specific channel from an administration channel.
I'm trying to get the channel object from the "send" command (l.20/35) in the "send_button_response" function (l.39).
Thanks in advance
send_button = interactions.Button(
custom_id = "send_button_id",
label = "Send",
style = interactions.ButtonStyle.SUCCESS
)
cancel_button = interactions.Button(
custom_id = "cancel_button_id",
label = "Cancel",
style = interactions.ButtonStyle.DANGER
)
row_buttons = interactions.ActionRow(
components = [send_button, cancel_button]
)
#bot.command(
name = "send",
description = "Send the message in the channel of your choice",
scope = [my scope],
options = [
interactions.Option(
name = "channel",
description = "The channel in which to send the message",
type = interactions.OptionType.CHANNEL,
channel_types = [0],
required = True
),
interactions.Option(
name = "message",
description = "The message to send",
type = interactions.OptionType.STRING,
required = True
)
]
)
async def send(ctx, channel, message):
await ctx.send(content = message, components = row_buttons, ephemeral = True)
#bot.component("send_button_id")
async def send_button_response(ctx):
# here the missing instruction to send the message to the specified channel
await ctx.edit(content = "Your message has been successfully sent to the [channel] channel.")
I'm trying to send an embed message with an image stored on my pc but the image appear above the embed message.
def function():
embedVar = discord.Embed(title="title", color="color")
embedVar.add_field(name = "name", value = "value", inline = False)
embedVar.add_field(name = "name", value = "value", inline = False)
embedVar.set_thumbnail(url = "attachment://filename.png")
return embedVar
embed = function()
await message.channel.send(embed = embed)
I have written the code to check if Twitch streamer is life, if so send a message, but i can't find a way to check if life notification(message and embed) is already send. So I tried different things of checking embed title: if discord.Embed(title=f":red_circle: **LIVE**\n{user.name} is now streaming on Twitch! \n \n {stream_data['data'][0]['title']}") == embed: and if discord.Embed(title=f":red_circle: **LIVE**\n{user.name} is now streaming on Twitch! \n \n {stream_data['data'][0]['title']}"):. But in the first case bot is spamming, in the second case bot doesn't activate else statement(which i need to send notification), so i am getting spammed or instead bot doesn't send anything at all. Please help me: I need balance, when streamer is live send ONE notification and then break(then check only if statement which must prevent bot from spamming. Here is the CODE. I recommend you taking a look between line 74 and 119. Especially line 99 with if statement.
import os
import json
import discord
import requests
from discord.ext import tasks, commands
from discord.utils import get
from server import ping
from Time import mytimemy
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='$', intents=intents)
TOKEN = os.getenv('token')
# Authentication with Twitch API.
client_id = os.getenv('client_id')
client_secret = os.getenv('Dweller_token')
body = {
'client_id': client_id,
'client_secret': client_secret,
"grant_type": 'client_credentials'
}
r = requests.post('https://id.twitch.tv/oauth2/token', body)
keys = r.json()
headers = {
'Client-ID': client_id,
'Authorization': 'Bearer ' + keys['access_token']
}
'''user_info = twitch.get_users(logins=['turb4ik'])
user_id = user_info['data'][0]['id']
print(user_info)'''
# Returns true if online, false if not.
def checkuser(streamer_name):
stream = requests.get('https://api.twitch.tv/helix/streams?user_login=' + streamer_name, headers=headers)
stream_data = stream.json()
if len(stream_data['data']) == 1:
return True, stream_data
else:
return False, stream_data
# Executes when bot is started
#bot.event
async def on_ready():
# Defines a loop that will run every 10 seconds (checks for live users every 10 seconds).
#tasks.loop(seconds=10)
async def live_notifs_loop():
# username = stream_data['data'][0]['user_name']
# stream_title = stream_data['data'][0]['title']
# game_being_played = stream_data['data'][0]['game_name']
# Opens and reads the json file
with open('streamers.json', 'r') as file:
streamers = json.loads(file.read())
# Makes sure the json isn't empty before continuing.
if streamers is not None:
# Gets the guild, 'twitch streams' channel, and streaming role.
guild = bot.get_guild(690995360411156531)
channel = bot.get_channel(785523710362124298)
role = get(guild.roles, id=835581408272580649)
# Loops through the json and gets the key,value which in this case is the user_id and twitch_name of
# every item in the json.
for user_id, twitch_name in streamers.items():
print("Checking" + " " + str(twitch_name) + " Current time: " + str(mytimemy()))
# Takes the given twitch_name and checks it using the checkuser function to see if they're live.
# Returns either true or false.
status, stream_data = checkuser(twitch_name)
# Gets the user using the collected user_id in the json
user = bot.get_user(int(user_id))
# Makes sure they're live
if status is True:
# Checks to see if the live message has already been sent.
async for message in channel.history(limit=200):
twitch_embed = discord.Embed(
title=f":red_circle: **LIVE**\n{user.name} is now streaming on Twitch! \n \n {stream_data['data'][0]['title']}",
color=0xac1efb,
url=f'\nhttps://www.twitch.tv/{twitch_name}'
)
twitch_embed.add_field(
name = '**Game**',
value = stream_data['data'][0]['game_name'],
inline = True
)
twitch_embed.add_field(
name = '**Viewers**',
value = stream_data['data'][0]['viewer_count'],
inline = True
)
twitch_embed.set_author(
name = str(twitch_name),
icon_url = stream_data['data'][0]['thumbnail_url']
)
twitch_embed.set_image(url = f'https://www.twitch.tv/{twitch_name}')
embeds = message.embeds
for embed in embeds:
if discord.Embed(title=f":red_circle: **LIVE**\n{user.name} is now streaming on Twitch! \n \n {stream_data['data'][0]['title']}") == embed:
try:
embed_title = twitch_embed.title
embed_description = twitch_embed.description
except Exception as e:
break
print(f"Already sent for {user.name} at {mytimemy()}!") #just sending the time and name
break
else:
# Gets all the members in your guild.
async for member in guild.fetch_members(limit=None):
# If one of the id's of the members in your guild matches the one from the json and
# they're live, give them the streaming role.
if member.id == int(user_id):
await member.add_roles(role)
# Sends the live notification to the 'twitch streams' channel then breaks the loop.
await channel.send(
content = f"Hey #everyone! {user.name} is now streaming on Twitch! Go check it out: https://www.twitch.tv/{twitch_name}", embed=twitch_embed)
print(f"{user} started streaming. Sending a notification.")
break
# If they aren't live do this:
else:
# Gets all the members in your guild.
async for member in guild.fetch_members(limit=None):
# If one of the id's of the members in your guild matches the one from the json and they're not
# live, remove the streaming role.
if member.id == int(user_id):
await member.remove_roles(role)
# Checks to see if the live notification was sent.
async for message in channel.history(limit=200):
try:
embed_title = message.embeds[0].title
embed_description = message.embeds[0].description
except Exception as e:
break
# If it was, delete it.
if str(user.name) in embed_title and "is now streaming" in embed_title:
print(f"{user} stopped streaming. Removing the notification.")
await message.delete()
# Start your loop.
live_notifs_loop.start()
# Command to add Twitch usernames to the json.
#bot.command(name='addtwitch', help='Adds your Twitch to the live notifs.', pass_context=True)
async def add_twitch(ctx, twitch_name):
# Opens and reads the json file.
with open('streamers.json', 'r') as file:
streamers = json.loads(file.read())
# Gets the users id that called the command.
user_id = ctx.author.id
# Assigns their given twitch_name to their discord id and adds it to the streamers.json.
streamers[user_id] = twitch_name
# Adds the changes we made to the json file.
with open('streamers.json', 'w') as file:
file.write(json.dumps(streamers))
# Tells the user it worked.
await ctx.send(f"Added {twitch_name} for {ctx.author} to the notifications list.")
ping()
print('Server Running')
bot.run(TOKEN)
It is very hard to explain and understand, but please help me. I need to check embed content while someone is streaming, so the embed and message are send one time per stream and NO spamming. And when stream goes off forget that embed content, so the embed can be send next time too. If u don't understand something, please ask. My discord just in case: Dweller_Igor#3291. Please someone EDIT the question, if it helps you better understand it.
MINIMAL REPRODUCIBLE EXAMPLE (embed, if-statement and else-statement):
if status is True:
# Checks to see if the live message has already been sent.
async for message in channel.history(limit=200):
twitch_embed = discord.Embed(
title=f":red_circle: **LIVE**\n{user.name} is now streaming on Twitch! \n \n {stream_data['data'][0]['title']}",
color=0xac1efb,
url=f'\nhttps://www.twitch.tv/{twitch_name}'
)
twitch_embed.add_field(
name = '**Game**',
value = stream_data['data'][0]['game_name'],
inline = True
)
twitch_embed.add_field(
name = '**Viewers**',
value = stream_data['data'][0]['viewer_count'],
inline = True
)
twitch_embed.set_author(
name = str(twitch_name),
icon_url = stream_data['data'][0]['thumbnail_url']
)
twitch_embed.set_image(url = f'https://www.twitch.tv/{twitch_name}')
embeds = message.embeds
for embed in embeds:
if discord.Embed(title=f":red_circle: **LIVE**\n{user.name} is now streaming on Twitch! \n \n {stream_data['data'][0]['title']}") == embed:
try:
embed_title = twitch_embed.title
embed_description = twitch_embed.description
except Exception as e:
break
print(f"Already sent for {user.name} at {mytimemy()}!") #just sending the time and name
break
else:
# Gets all the members in your guild.
async for member in guild.fetch_members(limit=None):
# If one of the id's of the members in your guild matches the one from the json and
# they're live, give them the streaming role.
if member.id == int(user_id):
await member.add_roles(role)
# Sends the live notification to the 'twitch streams' channel then breaks the loop.
await channel.send(
content = f"Hey #everyone! {user.name} is now streaming on Twitch! Go check it out: https://www.twitch.tv/{twitch_name}", embed=twitch_embed)
print(f"{user} started streaming. Sending a notification.")
break
await ctx.send(content = "some message", embed = embed)
It was a very stupid question at the time, and it still is to this day