discord.py 2.0 slash commands in cogs - python

I have had a lot of trouble getting slash commands to work in python 2.0. I found the code below and managed to make it work for me. However, I have no clue how to get it working in cogs. I even found this that uses a similar system.my load_extensions command also doesn't even work via the system below.
import discord
from discord import app_commands
import os, asyncio
class aclient(discord.Client):
def __init__(self):
super().__init__(intents = discord.Intents.default())
self.synced = False #we use this so the bot doesn't sync commands more than once
async def on_ready(self):
await self.wait_until_ready()
if not self.synced: #check if slash commands have been synced
await tree.sync() #guild specific: leave blank if global (global registration can take 1-24 hours)
self.synced = True
print(f"have logged in as {self.user}.")
client = aclient()
tree = app_commands.CommandTree(client)
#tree.command(name = 'hello', description='say hi!')
async def hello(interaction: discord.Interaction):
await interaction.response.send_message(f"Hi there!", ephemeral = True)
client.run("token")
async def load_extensions():
for filename in os.listdir('./cogs'):
if filename.endswith('.py'):
await client.load_extension(f'cogs.{filename[:-3]}')

https://gist.github.com/AbstractUmbra/a9c188797ae194e592efe05fa129c57f
The following gist details how to use slash commands even in cogs and is recommended in the official discord.py server.

Related

Import Tree Slash Commands from different file using discord.py

I'm learning how to create a discord bot using discord.py (still pretty new to python too).
I'm trying to implement multiple slash commands using app_commands Command Tree.
Here's a simplified version of my code (enough to explain my problem).
import discord
from discord import app_commands
guild_id = 'xxxxxx'
token = 'xxxxxx'
intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)
#client.event
async def on_ready():
await tree.sync(guild=discord.Object(id=guild_id))
print('Bot has started')
tree = app_commands.CommandTree(client)
#tree.command(name="listencouragements",
description="List all encouragements messages",
guild=discord.Object(id=guild_id))
async def listEncouragement(interaction: discord.Interaction):
print('List: [1, 2 ,3]')
#tree.command(name="moreecouragements",
description="More encouragements messages",
guild=discord.Object(id=guild_id))
async def listEncouragement(interaction: discord.Interaction):
print('This is more encouragements: [4, 5, 6]')
client.run(token)
I was trying to create a different file [slash.py] where I could put all tree.commands, and then import them in main file using load_extensions. Something like
# slash.py [This file is new, and I have
# no clue what to put here nor how to put here the commands]
import discord
from discord.ext import commands
#commands.hybrid_command()
async def hello(ctx):
await ctx.send(f"Hello {ctx.author.display_name}!")
async def setup(bot):
bot.add_command(hello)
#main.py
import slash
...
async def on_ready():
await [the bot object that I dont know].load_extension(slash)
...
I know that exists, but I have no clue how to do that. What's the object that has the .load_extension(slash)? Am I doing this the correct way?
load_extension is a method of commands.Bot.
You could've just typed load_extension into the search bar in the docs and gotten that exact same answer
In your case, you're using a Client instead of a Bot, which doesn't have access to any of these features. You're also using add_command(), which is also a method of Bot. If you want Bot-features, use a Bot. If you don't want Bot-features, choose whichever one you want.
Also, don't load extensions in on_ready. Extension loading should be done by overriding setup_hook.

How do i make a working slash command in discord.py

I am trying to make a slash command with discord.py I have tried a lot of stuff it doesn't seem to be working. Help would be appreciated.
Note: I will include a version for pycord at the end because I think it's much simpler, also it was the original answer.
discord.py version
First make sure that you have the newest version of discord.py installed.
In your code, you first import the library:
import discord
from discord import app_commands
and then you define your client and tree:
intents = discord.Intents.default()
client = discord.Client(intents=intents)
tree = app_commands.CommandTree(client)
The tree holds all of your application commands. Then you can define your command:
#tree.command(name = "commandname", description = "My first application Command", guild=discord.Object(id=12417128931)) #Add the guild ids in which the slash command will appear. If it should be in all, remove the argument, but note that it will take some time (up to an hour) to register the command if it's for all guilds.
async def first_command(interaction):
await interaction.response.send_message("Hello!")
Then you also have to sync your commands to discord once the client is ready, so we do that in the on_ready event:
#client.event
async def on_ready():
await tree.sync(guild=discord.Object(id=Your guild id))
print("Ready!")
And at the end we have to run our client:
client.run("token")
pycord version
To install py-cord, first run pip uninstall discord.py and then pip install py-cord.
Then in your code, first import the library with
import discord
from discord.ext import commands
create you bot class with
bot = commands.Bot()
and create your slash command with
#bot.slash_command(name="first_slash", guild_ids=[...]) #Add the guild ids in which the slash command will appear. If it should be in all, remove the argument, but note that it will take some time (up to an hour) to register the command if it's for all guilds.
async def first_slash(ctx):
await ctx.respond("You executed the slash command!")
and then run the bot with your token
bot.run(TOKEN)
They're sort of in the middle of adding slash commands to discord.py but you can see a few examples in https://gist.github.com/Rapptz/c4324f17a80c94776832430007ad40e6 You seem to be using discord_slash, which I have not used.
The main documentation for this stuff is https://discordpy.readthedocs.io/en/master/interactions/api.html?highlight=dropdown#decorators but the main "how to" is that you've gotta make a "tree", attach commands to that tree, and sync your tree for the commands to show up. discord.ext.Bot makes its own tree, which is why I'm using that instead of client, which I think doesn't make a tree by default.
If you specify the guilds, the commands sync takes place instantly, but if you don't specify the guild, I think it takes an hour to update or something like that, so specify the guild until you're ready for deployment.
I'm not quite sure how to do it in cogs, because I have mine in groups but basically what I'm doing is a combination of #bot.tree.command() in the main bot file and a few groups in separate files.
So here's my main file
import discord
import simplegeneralgroup
from config import TOKEN
MY_GUILD = discord.Object(id=1234567890)
class MyBot(discord.ext.commands.Bot):
async def on_ready(self):
await self.tree.sync(guild=MY_GUILD)
bot: discord.ext.commands.Bot = MyBot
#bot.tree.command(guild=MY_GUILD)
async def slash(interaction: discord.Interaction, number: int, string: str):
await interaction.response.send_message(f'Modify {number=} {string=}', ephemeral=True)
bot.tree.add_command(simplegeneralgroup.Generalgroup(bot), guild=MY_GUILD)
if __name__ == "__main__":
bot.run(TOKEN)
and then the simplegeneralgroup file
import discord
from discord import app_commands as apc
class Generalgroup(apc.Group):
"""Manage general commands"""
def __init__(self, bot: discord.ext.commands.Bot):
super().__init__()
self.bot = bot
#apc.command()
async def hello(self, interaction: discord.Interaction):
await interaction.response.send_message('Hello')
#apc.command()
async def version(self, interaction: discord.Interaction):
"""tells you what version of the bot software is running."""
await interaction.response.send_message('This is an untested test version')
There should be three commands: /slash, which will prompt the user for a number and string, /generalgroup hello, and /generalgroup version
# This is new in the discord.py 2.0 update
# imports
import discord
import discord.ext
# setting up the bot
intents = discord.Intents.all()
# if you don't want all intents you can do discord.Intents.default()
client = discord.Client(intents=intents)
tree = discord.app_commands.CommandTree(client)
# sync the slash command to your server
#client.event
async def on_ready():
await tree.sync(guild=discord.Object(id=Your guild ID here))
# print "ready" in the console when the bot is ready to work
print("ready")
# make the slash command
#tree.command(name="name", description="description")
async def slash_command(int: discord.Interaction):
await int.response.send_message("command")
# run the bot
client.run("token")
discord.py does not support slash commands. I recommend you use discord-py-interactions for slash commands. To install it is to do python3.exe -m pip install discord-py-interactions. It works well. Here is a sample code to base off:
import interactions
bot = interactions.Client(token="your_secret_bot_token")
#bot.command(
name="my_first_command",
description="This is the first command I made!",
scope=the_id_of_your_guild,
)
async def my_first_command(ctx: interactions.CommandContext):
await ctx.send("Hi there!")
bot.start()
Slash Commands with discord.py (2.0)
While this is a new answer to an old question when I first started coding a bot I ran into this but non of the answers worked.
Some Context: There are 2 ways to code a slash command in discord.py 2.0
discord.Client, +Easy to Sync -No Prefix Commands
commands.Bot, -Harder to Sync +Prefix Commands
I will show one examples I am more confidant on the commands.Bot FYI
A great external source for discord.Client slash command examples is Rapptz-app_command_examples
commands.Bot Slash Command
from typing import Literal, Optional
import discord
from discord.ext.commands import Greedy, Context
from discord import app_commands
from discord.ext import commands
#------ Bot ------
# Can add command_prefix='!', in commands.Bot() for Prefix Commands
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
bot = commands.Bot(intents=intents)
#--- Bot Startup
#bot.event
async def on_ready():
print(f'Logged in as {bot.user}') #Bot Name
print(bot.user.id) #Bot ID
#------ Slash Commands ------
#Parameters can be added in def help()
# Ex- async def help(interaction: discord.Interaction, left:int,right:int)
#bot.tree.command()
async def help(interaction: discord.Interaction):
"""Help""" #Description when viewing / commands
await interaction.response.send_message("hello")
#------ Sync Tree ------
guild = discord.Object(id='guildID')
# Get Guild ID from right clicking on server icon
# Must have devloper mode on discord on setting>Advance>Developer Mode
#More info on tree can be found on discord.py Git Repo
#bot.command()
#commands.guild_only()
#commands.is_owner()
async def sync(
ctx: Context, guilds: Greedy[discord.Object], spec: Optional[Literal["~", "*", "^"]] = None) -> None:
if not guilds:
if spec == "~":
synced = await ctx.bot.tree.sync(guild=ctx.guild)
elif spec == "*":
ctx.bot.tree.copy_global_to(guild=ctx.guild)
synced = await ctx.bot.tree.sync(guild=ctx.guild)
elif spec == "^":
ctx.bot.tree.clear_commands(guild=ctx.guild)
await ctx.bot.tree.sync(guild=ctx.guild)
synced = []
else:
synced = await ctx.bot.tree.sync()
await ctx.send(
f"Synced {len(synced)} commands {'globally' if spec is None else 'to the current guild.'}"
)
return
ret = 0
for guild in guilds:
try:
await ctx.bot.tree.sync(guild=guild)
except discord.HTTPException:
pass
else:
ret += 1
await ctx.send(f"Synced the tree to {ret}/{len(guilds)}.")
bot.run('token')
!sync -> global/server sync (No ID) or (ID SET)
!sync ~ -> sync current guild (Bot In)
!sync * -> copies all global app commands to current guild and syncs
!sync ^ -> clears all commands from the current guild target and syncs (removes guild commands)
!sync id_1 id_2 -> syncs guilds with id 1 and 2
If I had made any errors please comment and I will fix them, goodluck on your discord bot journey
discord.py does not support slash commands and will never add support for slash commands (as it has shut down) thus I recommend disnake (a popular fork). Specifically disnake because out of all the forks disnake seems to be the more intellectual one.

Why is my slash command not displayed despite correct usage?

I am currently working with the discord-py-slash-command library and have read through the documentation here: https://discord-py-slash-command.readthedocs.io/en/latest/quickstart.html
But for whatever reason it doesn't work, the command is not recognized/on the two servers, and the private messages of the bot the slash command doesn't show up.
I know that discord.py doesn't support slash commands yet, but this lib actually seems to work, at least from what I saw. Does anyone here see the mistake I made? I followed tons of tutorials with no success...
I already removed sync_commands=True or even tried to remove guild_ids and then wrote a message to the bot. Global commands take up to an hour to be displayed, but I actually avoid that with guild_ids.
Here is my code so far:
import discord
from discord.ext import commands
from discord_slash import SlashCommand # The lib
intents = discord.Intents.all()
client = commands.Bot(command_prefix="-", intents=intents)
slash = SlashCommand(client, sync_commands=True)
TOKEN = "..."
#client.event
async def on_ready():
print("Ready!")
print(slash.commands)
# Prints: {'ping': <discord_slash.model.BaseCommandObject object at 0x000002184B23E708>}
guild_ids = [812510632360149XXX, 871078836870185XXX]
# Directly from the docs!
#slash.slash(name="Ping", description="Ping command", guild_ids=guild_ids)
async def _ping(ctx): # Defines a new "context" (ctx) command called "ping."
await ctx.send("Pong!")
#client.command(name="test") # Test command which works
async def test(ctx):
await ctx.send("test")
client.run(TOKEN)
I also looked at other questions like: Discord.py | Slash commands aren’t working but they did not help either. Is this a problem with how I code/the program? (PyCharm)
You first have to set it to "True" in the App Settings of Discord. Here we turn on Text Box and can now use Slash commands, Most of the time this will be the error, because your code itself does not contain any, at least from what I have tested.
Here is a picture:
What about PRESENCE INTENT and SERVER MEMBERS INTENT in bot settings? cause i copied your code and tried to run, it worked for me. I've attached the images here. https://imgur.com/a/S0IuSlY
import discord
from discord.ext import commands
from discord_slash import SlashCommand # The lib
intents = discord.Intents.all()
client = commands.Bot(command_prefix="-", intents=intents)
slash = SlashCommand(client, sync_commands=True)
#client.event
async def on_ready():
print("Ready!")
guild_ids = [85528118773940xxxxx]
#slash.slash(name="Ping", description="Ping command", guild_ids=guild_ids)
async def _ping(ctx): # Defines a new "context" (ctx) command called "ping."
await ctx.send("Pong!")
#client.command(name="test") # Test command which works
async def test(ctx):
await ctx.send("test")
client.run('token')

How to execute a python discord bot function in another python script?

I am trying to create a python script that would mute the users of a specific voice channel when executed. Till now I am able to mute everyone by typing the command in the discord text channel, but I would like to mute everyone when another python script tells the bot to. Below is my attempt to do that.
bot.py is the python discord bot:
import discord
from discord.ext import commands
from time import sleep
client = commands.Bot(command_prefix="./")
#client.event
async def on_ready():
print("Bot is online. ")
#client.command()
async def play_music_test():
channel = await client.get_channel(voice_channel_number)
voice = await channel.connect()
await voice.play(
discord.FFmpegPCMAudio(executable="C:/Users/USER/ffmpeg/bin/ffmpeg.exe",
source="C:/Users/USER/Desktop/song.mp3"))
client.run(TOKEN)
abc.py is the other python script trying to call a function:
from bot import play_music_test
import asyncio
print("")
asyncio.run(play_music_test())
I ran the bot.py first and then tried to execute the abc.py next, bot came online but when executing abc.py, it didn't print or do anything at all. I just started to learn discord.py so if this is a silly question, forgive me.
Instead of running the python file you can import it, or making it a cog
heres an example:
importing: bot.py
import discord
from discord.ext import commands
from time import sleep
from abc import *
client = commands.Bot(command_prefix="./")
#client.event
async def on_ready():
print("Bot is online. ")
#client.command(name = "play_music", aliases = ["you can asign aliases like this", "multiple ones too"])
async def play_music_test(ctx, channel): # If the python file doesn't know what channel is, it can be asigned when calling the function in discord, think of it like sys.argv or argparse
if channel == None: channel = ctx.channel # This sets the current channel you are in if none was provided when executing it in discord
# channel = await client.get_channel(channel) now you don't need this line
voice = await channel.connect()
await voice.play(
discord.FFmpegPCMAudio(executable="C:/Users/USER/ffmpeg/bin/ffmpeg.exe",
source="C:/Users/USER/Desktop/song.mp3"))
client.run(TOKEN)
importing: abc.py
remove asyncio.run(play_music_test())
use it in discord instead! ex. play_music_test #general
Making it a cog: bot.py
import discord
from discord.ext import commands
from time import sleep
import os
client = commands.Bot(command_prefix="./")
#client.event
async def on_ready():
print("Bot is online. ")
for filename in os.listdir("./"):
if filename == "bot.py": continue
else: client.load_extension(f"cogs.{filename[:-3]}")
client.run(TOKEN)
Making it a cog: abc.py
from bot import play_music_test
import asyncio
class Mycog(commands.Cog):
def __init__(self, client):
self.client = client
#client.command(name = "play_music", aliases = ["you can asign aliases like this",
"multiple ones too"])
async def play_music_test(ctx, channel): # If the python file doesn't know what
channel is, it can be asigned when calling the function in discord, think of it like sys.argv or argparse
if channel == None: channel = ctx.channel # This sets the current channel you are in if none was provided when executing it in discord
# channel = await client.get_channel(channel) now you don't need this line
voice = await channel.connect()
await voice.play(
discord.FFmpegPCMAudio(executable="C:/Users/USER/ffmpeg/bin/ffmpeg.exe",
source="C:/Users/USER/Desktop/song.mp3"))
def setup(client):
client.add_cog(Mycog(client))
This anwser is not the best but hope this helps!
i'm not sure, if i really understand, what you try to do, but to open a script from another script, i use subprocess.Popen()
but i think, in your case it fits more, to change the way you try to solve your problem. maybe you should take a look into the on_message event and use message.content
?
You can importing your client variable (from bot import play_music_test, client) and then client.loop.create_task(play_music_test())
(Although I do not understand why you would do such a thing)

Discord bot doesn't respond to commands after moved them to cog [duplicate]

This question already has answers here:
Why does on_message() stop commands from working?
(2 answers)
Closed 3 years ago.
Few days ago I decided to move all commands in my Discord Bot into an extension/cog file. After that Discord completely ignore any command (even these declared in main file). Logs are fine, there's no error or crashes. I tried many methods, that I found here, on youtube, github etc
Here is the main code:
import discord
from discord.ext import commands
import asyncio
import random
import string
import requests
import json
import os
bot = commands.Bot(command_prefix = '?')
extensions = ['cogs.com']
if __name__ == '__main__':
for extension in extensions:
try:
bot.load_extension(extension)
except Exception as error:
print('{} cannot load the file. [{}]'.format(extension, error))
#bot.event
async def on_ready():
await bot.change_presence(game=discord.Game(name="type `?help` for help"))
print('Logged in as')
print(bot.user.name)
print(bot.user.id)
print('------')
#bot.event
async def on_message(message):
# here I've got a lot of bot events (responding, sending funny memes etc). Surprisingly this part works absolutely fine
bot.run("TOKEN", bot=True, reconnect=True)
And the cog file (com.py). Here I've got a lot of commands, but I decided to leave only the basic one:
import discord
from discord.ext import commands
class Com():
def __init__(self, bot):
self.bot = bot
#commands.command()
async def test(self):
print('TEST') # Logs don't show anything after my command. It looks like bot doesn't even read it... or read it and doesn't send anything back?
await self.bot.send('test')
def setup(bot):
bot.add_cog(Com(bot))
(discord.py ver = 0.16.12)
If anyone could help, that would be awesome. Thanks
After a short break, I returned to this problem and I solved it by adding:
await bot.process_commands(message)
at the end of:
#bot.event
async def on_message(message):
I completely forgot about this line. That's why bot ignored my commands.
Thanks everybody, have a nice day

Categories

Resources