-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
416 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
.vscode/ | ||
|
||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,58 @@ | ||
# discord-py-interactions_boilerplate | ||
Boilerplate template for the discord-py-interactions library | ||
<h3 align=center>Boilerplate template for the discord-py-interactions library</h3> | ||
<hr> | ||
|
||
- **Currently, this boilerplate supports `discord-py-interactions==3.0.2` but will be updated for future version later on. To switch to a different version, check the branches** | ||
|
||
# Overview | ||
> `main.py:` | ||
- A custom, dynamic cog loader is present. Write a cog following the `template.py` in `/cogs/`, place it in the `/cogs/` directory, and it will automatically be loaded when the bot boots. | ||
- Utilizes the logging library and implements an easy to use custom logger and formatter. All you need to do is call `initLogger("script_name")` in a module or cog, and log configuration is taken care of for you. | ||
- Alongside the custom logging utility, exception handling is present and proper debug levels exist. You can configure the level to your liking in `config.py`. Also, this handles command cooldown if you define it in your cogs. | ||
|
||
> `src/logutil.py:` | ||
- Functions here exist to aid the user in simplifying `logging` configuration. Here, all log messages go to standard output. | ||
- A custom formatter also applies based on what level logging you desire, whereas DEBUG produces verbose output and is tailored to aid in debugging, showing which module the message is originating from and, in most cases, which line number. Loggging levels are categorized by color. | ||
|
||
> `cogs/template.py:` | ||
- This example cog is documented extensively. Please be sure to read over it. This cog will *not* be loaded on boot, so please refrain from writing your code in it. | ||
|
||
> `config.py:` | ||
- This module houses the basic configuration options for your bot, including DEBUG switches and the bot prefix. | ||
|
||
# Installation | ||
> 1. Clone this repository. To switch to a different version, `cd` into this cloned repository and run `git checkout -b [branch name/version here]` | ||
> 2. Create a Discord bot token from [here](https://discord.com/developers/applications/) | ||
> **Register it for slash commands:** | ||
> - Under *OAuth2 > General*, set the Authorization Method to "In-app Authorization" | ||
> - Tick `bot` and `applications.commands` | ||
> - Go to *OAuth2 > URL Generator*, tick `bot` and `applications.commands`. For Bot Permissions, tick: | ||
> > - General: Read Messages/View Channels | ||
> > - Text Permissions: Send Messages, Manage Messages, and Embed Links | ||
> - Copy the generated URL at the bottom of the page to invite it to desired servers | ||
> 3. Make a new file called `.env` inside the repo folder and paste the below code block in the file | ||
> ``` | ||
> TOKEN="[paste Discord bot token here]" | ||
> DEV_GUILD=[paste your bot testing server ID here] | ||
> ``` | ||
> 4. Run `pip install -r requirements.txt` to install packages. You'll need Python 3.6.8 or later | ||
> 5. Once that's done, run the bot by executing `python3 main.py` in the terminal | ||
> | ||
> <hr /> | ||
> | ||
> *If you aren't sure how to obtain your server ID, check out [this article](https://www.alphr.com/discord-find-server-id/)* | ||
> | ||
> *If you get errors related to missing token environment variables, run `source .env`* | ||
# FAQ | ||
## Why aren't my slash commands getting registered? | ||
> There could be many reasons, but let's narrow it down | ||
> - Ensure your bot token has the `applications.command` scope before you invited your bot. If not, kick the bot from your server(s), follow above directions to enable the permissions scope, and reinvite. | ||
> - The bot uses a guild ID to register the slash commands in a single guild. This ensures it will be registered instantly. In order to use slash commands globally, remove the `guild_ids=[]` in your `@cog_ext.cog_slash` decorators. But **keep in mind this may take a few hours to register.** To refresh it instantly, simply kick the bot from your server and reinvite. | ||
<hr /> | ||
## Why am I getting a `HTTP 403 - 50001 Missing Access`? | ||
> Again, like above, this could be caused by many different reasons, but here are a couple things you can try | ||
> - Follow the above steps to ensure your slash commands are registering properly (making sure `applications.command` is enabled, etc.) | ||
> - Reinvite your bot |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
""" | ||
Example cog for real world use | ||
This is safe to delete | ||
""" | ||
|
||
import os | ||
|
||
from discord.ext import commands | ||
from discord_slash import cog_ext | ||
|
||
from src import logutil # pylint: disable=import-error | ||
Cog = commands.Cog | ||
|
||
logger = logutil.init_logger("helloworld.py") | ||
|
||
DEV_GUILD = int(os.environ.get("DEV_GUILD")) | ||
|
||
|
||
class HelloWorld(commands.Cog): | ||
"Main class for the bot" | ||
def __init__(self, client): | ||
self.client = client | ||
|
||
@Cog.listener() | ||
async def on_ready(self): | ||
"Called when cog is loaded" | ||
logger.info("HelloWorld slash cog registered") | ||
|
||
async def command(self, ctx): | ||
""" | ||
Your command code goes here | ||
""" | ||
await ctx.send("Hello world!") | ||
|
||
@commands.command(name="helloworld") | ||
async def _reg_prefixed(self, ctx): | ||
"This function registers your command as a normal bot command" | ||
await self.command(ctx,) | ||
|
||
@cog_ext.cog_slash(name="helloworld", | ||
description="Hello world!", | ||
guild_ids=[DEV_GUILD]) | ||
async def _slash_prefixed(self, ctx,): | ||
"This function registers your command as a slash command" | ||
await self.command(ctx,) | ||
|
||
|
||
def setup(bot): | ||
"Called when this cog initializes" | ||
bot.add_cog(HelloWorld(bot)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
""" | ||
This file provides a template for future commands. This file will not be loaded as a cog or module | ||
""" | ||
|
||
import os | ||
|
||
from discord.ext import commands | ||
# You will need to import cog_ext from discord_slash in order to use slash commands | ||
from discord_slash import cog_ext | ||
|
||
# Import required Discord libraries | ||
# Highly recommended - we suggest providing proper debug logging | ||
from src import logutil # pylint: disable=import-error | ||
Cog = commands.Cog | ||
|
||
# Change this - this labels log messages for debug mode | ||
logger = logutil.init_logger("template.py") | ||
|
||
# Use the DEV_GUILD environment variable to instantly load slash commands in your testing guild | ||
# Global slash commands are usually cached for an hour due to Discord API restrictions. | ||
DEV_GUILD = int(os.environ.get("DEV_GUILD")) | ||
|
||
|
||
# Rename this class to whatever you'd like. Rename it again below at setup() | ||
class Command(commands.Cog): | ||
"Main class for bot" | ||
def __init__(self, client): | ||
self.client = client | ||
|
||
@Cog.listener() | ||
async def on_ready(self): # code to execute when cog has been loaded | ||
"Called when cog is initialized" | ||
logger.info("Command slash cog registered") | ||
|
||
# Pass all arguments as "args" and default to NoneType | ||
async def command(self, ctx, *, args: str = None): | ||
""" | ||
Your command code goes here | ||
""" | ||
|
||
# These two functions exist so that your command will respond both to the bot prefix | ||
# and slash commands. | ||
# -- | ||
# Set this to a command name. This will be called with your server's prefix (eg. rf.command) | ||
@commands.command(name="command") | ||
async def _reg_prefixed(self, ctx): | ||
"This function registers your command as a normal bot command" | ||
# If your function name is different, change it here | ||
await self.command(ctx,) | ||
|
||
# Set this to your command name (eg: /command) and add a meaningful description. | ||
# Don't forget to specify a value of [DEV_GUILD] to the guild_ids argument or | ||
# your slash commands won't instantly load! | ||
@cog_ext.cog_slash(name="command", | ||
description="Some description for the command", | ||
guild_ids=[DEV_GUILD]) | ||
async def _slash_prefixed(self, ctx,): | ||
"This function registers your command as a slash command" | ||
# If your function name is different, change it here | ||
await self.command(ctx,) | ||
|
||
|
||
def setup(bot): | ||
"Called when cog is initializing" | ||
# Required for cog to register | ||
bot.add_cog(Command(bot)) # Don't forget to rename the class here! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
"Enable DEBUG messages for logging" | ||
DEBUG = False | ||
|
||
"Enable verbose DEBUG Discord.py messages for logging" | ||
DEBUG_DISCORD = False | ||
|
||
"Bot prefix to respond to" | ||
PREFIX = "#" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
""" | ||
Main script to run | ||
This script initializes cogs and starts the bot | ||
Code taken from my contributions in: | ||
https://github.com/savioxavier/repo-finder-bot/ | ||
Additional thanks to savioxavier | ||
""" | ||
import os | ||
import sys | ||
|
||
import discord | ||
from discord.ext import commands | ||
from discord.ext.commands.errors import ExtensionFailed, NoEntryPointError | ||
from discord_slash import SlashCommand | ||
from dotenv import load_dotenv | ||
|
||
from src import logutil | ||
from config import DEBUG, DEBUG_DISCORD | ||
from config import PREFIX as bot_prefix | ||
|
||
load_dotenv() | ||
|
||
# Configure logging for this main.py handler | ||
logger = logutil.init_logger("main.py") | ||
|
||
# Configure logging for Discord.py | ||
if DEBUG: | ||
logging = logutil.get_logger("discord") | ||
|
||
logger.warning("Debug mode is %s; Discord debug is %s", DEBUG, DEBUG_DISCORD) | ||
|
||
# Instantiate environment variables | ||
DEV_GUILD = [int(os.environ.get("DEV_GUILD"))] | ||
TOKEN = os.environ.get("TOKEN") | ||
|
||
intents = discord.Intents.default() | ||
intents.members = True # pylint: disable=assigning-non-slot # noqa | ||
|
||
# Define the client | ||
client = commands.Bot(command_prefix=bot_prefix, | ||
case_insensitive=True, | ||
intents=intents, | ||
help_command=None, | ||
) | ||
|
||
# Define the slash command handler | ||
slash = SlashCommand(client, | ||
sync_commands=True, | ||
sync_on_cog_reload=True,) | ||
|
||
|
||
# BEGIN on_ready | ||
async def on_ready(): | ||
"Called when bot is ready to receive interactions" | ||
logger.info( | ||
"Logged in as %s#%s", | ||
client.user.name, | ||
client.user.discriminator | ||
) | ||
# END on_ready | ||
|
||
# BEGIN command_help | ||
async def command_help(ctx): | ||
"Help command" | ||
logger.debug("%s - initiated help command", | ||
ctx.message.author) | ||
|
||
try: | ||
_created_at = ctx.message.created_at | ||
except AttributeError: | ||
_created_at = ctx.created_at | ||
|
||
help_embed = discord.Embed( | ||
title="Help", | ||
description="Fill me in!", | ||
timestamp=_created_at | ||
) | ||
|
||
help_embed.set_thumbnail(url=client.user.avatar_url) | ||
help_embed.set_footer(text="Boilerplate Bot") | ||
|
||
await ctx.send(embed=help_embed) | ||
# END command_help | ||
|
||
# BEGIN on_command_error | ||
async def on_command_error(ctx: commands.Context, error): | ||
"Gets called when a command fails" | ||
if isinstance(error, commands.CommandOnCooldown): | ||
# handle cooldown | ||
logger.debug( | ||
"%s - initiated a command on cooldown [!]" | ||
) | ||
await ctx.send( | ||
f"This command is on cooldown. Try again after `{round(error.retry_after)}` seconds.", | ||
delete_after=5 | ||
) | ||
else: | ||
# handle anything else | ||
logger.warning( | ||
"A discord.py command error occured:\n%s", | ||
error | ||
) | ||
await ctx.send( | ||
f"A discord.py command error occured:\n{error}", | ||
delete_after=10 | ||
) | ||
# END on_command_error | ||
|
||
# BEGIN cogs_dynamic_loader | ||
|
||
# Fill this array with Python files in /cogs | ||
# This omits __init__.py, template.py, and excludes files without a py file extension | ||
command_modules = [ | ||
module[:-3] | ||
for module in os.listdir(f"{os.path.dirname(__file__)}/cogs") | ||
if module not in ("__init__.py", "template.py") and module[-3:] == ".py" | ||
] | ||
|
||
if command_modules or command_modules == []: | ||
logger.info( | ||
"Importing %s cogs: %s", | ||
len(command_modules), | ||
', '.join(command_modules) | ||
) | ||
else: | ||
logger.warning("Could not import any cogs!") | ||
|
||
for module in command_modules: | ||
try: | ||
client.load_extension("cogs." + module) | ||
except NoEntryPointError: | ||
logger.error( | ||
"Could not import cog %s: The cog has no setup function - NoEntryPointError", | ||
module | ||
) | ||
logger.debug(str(sys.exc_info()[2])) | ||
except ExtensionFailed: | ||
logger.error( | ||
"Could not import cog %s: The cog failed to execute", | ||
module | ||
) | ||
logger.debug(str(sys.exc_info()[2])) | ||
except Exception as e: # pylint: disable=broad-except | ||
logger.error( | ||
"Could not import cog %s:\n%s", | ||
module, | ||
e | ||
) | ||
|
||
logger.info("Cog initialization complete") | ||
logger.debug( | ||
"Cogs incoming:\n%s\n", | ||
',\n'.join(command_modules) | ||
) | ||
# END cogs_dynamic_loader | ||
|
||
client.run(TOKEN) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
discord-py-interactions==3.0.2 | ||
discord.py==1.7.3 | ||
requests==2.26.0 | ||
discord==1.7.3 | ||
python-dotenv==0.19.1 | ||
aiohttp[speedups] |
Oops, something went wrong.