forked from viveksantayana/geas-bot
Vivek Santayana
1d355e3b2d
Changed virtual environment settings. Beginning change to data structure.
140 lines
5.5 KiB
Python
140 lines
5.5 KiB
Python
import os, sys # OS Locations
|
|
from dotenv import load_dotenv # Import OS variables from Dotenv file.
|
|
load_dotenv() # Load Dotenv. Delete this for production
|
|
import yaml # Parser for yaml files for config settings.
|
|
import asyncio # Discord Py Dependency
|
|
import discord # Main Lib
|
|
from discord.ext import commands # Commands module
|
|
from discord_slash import SlashCommand, SlashContext, cog_ext, utils # Slash Command Library
|
|
from discord_slash.utils.manage_commands import create_choice, create_option # Slash Command features
|
|
import logging
|
|
|
|
## Define YAML functions
|
|
|
|
def yaml_load(filepath:str):
|
|
### Loads a YAML file
|
|
with open(filepath, 'r') as file:
|
|
data = yaml.load(file, Loader=yaml.FullLoader)
|
|
return data
|
|
|
|
def yaml_dump(data:dict, filepath:str):
|
|
### Dumps a YAML file
|
|
with open(filepath, 'w') as file:
|
|
yaml.dump(data, file)
|
|
|
|
# Locate or create config file
|
|
configFile = os.getenv('CONFIG') if os.getenv('CONFIG').endswith('.yml') else './data/config.yml'
|
|
|
|
if not os.path.exists(configFile):
|
|
yaml_dump({},configFile)
|
|
|
|
# Locate or create data file
|
|
dataFile = os.getenv('DATA') if os.getenv('DATA').endswith('.yml') else './data/data.yml'
|
|
|
|
if not os.path.exists(dataFile):
|
|
yaml_dump({},dataFile)
|
|
|
|
# Locate Cogs Directory
|
|
cogsDir = 'cogs'
|
|
|
|
# --> Temporary disable logging because of verboseness.
|
|
# ## Logging configuration imported boilerplate from Discord Py Docs
|
|
# logger = logging.getLogger('discord')
|
|
# logger.setLevel(logging.DEBUG)
|
|
# handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w')
|
|
# handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
|
|
# logger.addHandler(handler)
|
|
|
|
#### Dynamic Prefixes
|
|
def getPrefix(client, message):
|
|
conf = yaml_load(configFile)
|
|
return conf[str(message.guild.id)]['prefix']
|
|
|
|
# Define Clients
|
|
client = commands.Bot(
|
|
intents=discord.Intents.all(),
|
|
command_prefix=getPrefix
|
|
)
|
|
slash = SlashCommand(
|
|
client,
|
|
sync_commands = True,
|
|
sync_on_cog_reload = True
|
|
)
|
|
# sync_on_reload is an important parameter that will become relevant when having to reload cogs on changing bot configs.
|
|
|
|
# Define Config keys
|
|
|
|
def setConfig(guild:discord.Guild):
|
|
#### Check if the bot is missing any config entries for the guilds it is in, and if it is then add it in.
|
|
#### N.B.: The way the commands work, the bot will have to list specific guilds in which it will synchronise the commands when it is defining them. So it needs to give a list of all the guilds it is part of when the bot loads, which it draws from the config files.
|
|
#### Because the bot connects to Discord after it loads, it will not be able to introspect and see what guilds it is part of before the commands are first loaded, and it will only add new guilds to the config files after it has already connected.
|
|
#### The Bot will first need to set up all of its configurations, and then begin loading all other commands once it is ready.
|
|
conf = yaml_load(configFile)
|
|
guildStr = str(guild.id)
|
|
if guildStr not in conf:
|
|
conf[guildStr] = {}
|
|
if 'name' not in conf[guildStr] or conf[guildStr]['name'] != guild.name:
|
|
conf[guildStr]['name'] = guild.name
|
|
if 'configured' not in conf[guildStr] or conf[guildStr]['configured'] is not bool:
|
|
conf[guildStr]['configured'] = False
|
|
if 'owner' not in conf[guildStr] or conf[guildStr]['owner'] != guild.owner_id:
|
|
conf[guildStr]['owner'] = guild.owner_id
|
|
if 'roles' not in conf[guildStr] or (type(conf[guildStr])['roles'] is not dict or len(conf[guildStr]['roles']) == 0 or None in conf[guildStr]['roles']):
|
|
conf[guildStr]['roles'] = {}
|
|
if 'admin' not in conf[guildStr]['roles'] or (type(conf[guildStr]['roles']['admin']) is not list or len(conf[guildStr]['roles']['admin']) == 0 or None in conf[guildStr]['roles']['admin']):
|
|
conf[guildStr]['roles']['admin'] = []
|
|
for role in guild.roles:
|
|
if not (role.is_bot_managed() or role.is_integration()) and role.permissions.administrator:
|
|
conf[guildStr]['roles']['admin'].append(role.id)
|
|
if 'prefix' not in conf[guildStr]:
|
|
conf[guildStr]['prefix'] = '-'
|
|
if 'modchannel' not in conf[guildStr]:
|
|
if guild.system_channel is None:
|
|
p = len(guild.channels)
|
|
c = None
|
|
for t in guild.text_channels:
|
|
if t.position < p:
|
|
p = t.position
|
|
conf[guildStr]['modchannel'] = t.id
|
|
else:
|
|
conf[guildStr]['modchannel'] = guild.system_channel.id
|
|
yaml_dump(conf, configFile)
|
|
|
|
def clearConfig(guildKey:str):
|
|
#### Delete Configs for Guilds that the Bot is no longer in
|
|
conf = yaml_load(configFile)
|
|
if discord.utils.find(lambda g: str(g.id) == guildKey, client.guilds) is None:
|
|
del conf[guildKey]
|
|
yaml_dump(conf, configFile)
|
|
|
|
def loadCog(filepath:str):
|
|
path = os.path.normpath(filepath).split(os.path.sep)
|
|
if path[-1].endswith('.py'):
|
|
path[-1] = path[-1][:-3]
|
|
client.load_extension('.'.join(path))
|
|
|
|
def unloadCog(filepath:str):
|
|
path = os.path.normpath(filepath).split(os.path.sep)
|
|
if path[-1].endswith('.py'):
|
|
path[-1] = path[-1][:-3]
|
|
client.unload_extension('.'.join(path))
|
|
|
|
def loadCogs(cogClass:str = 'all'):
|
|
for category in os.listdir(f'./{cogsDir}'):
|
|
if cogClass == 'all' or cogClass == category:
|
|
for cogfile in os.listdir(f'./{cogsDir}/{category}'):
|
|
if cogfile.endswith('.py'):
|
|
loadCog(f'./{cogsDir}/{category}/{cogfile}')
|
|
|
|
def unloadCogs(cogClass:str = 'all'):
|
|
for category in os.listdir(f'./{cogsDir}'):
|
|
if cogClass == 'all' or cogClass == category:
|
|
for cogfile in os.listdir(f'./{cogsDir}/{category}'):
|
|
if cogfile.endswith('.py'):
|
|
unloadCog(f'./{cogsDir}/{category}/{cogfile}')
|
|
|
|
loadCogs('dev')
|
|
loadCogs('events')
|
|
loadCogs('botcommands')
|
|
|
|
client.run(os.getenv('TEST_3_TOKEN')) |