aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--README.md2
-rw-r--r--code/bot.py59
-rw-r--r--code/cogs/help.py3
-rw-r--r--code/cogs/lyrics.py78
-rw-r--r--code/cogs/play.py8
-rw-r--r--code/utils/config.py372
-rw-r--r--config.ini.example18
-rw-r--r--config.yaml.example0
-rw-r--r--docker-compose.yaml16
-rw-r--r--requirements.txt5
11 files changed, 331 insertions, 233 deletions
diff --git a/.gitignore b/.gitignore
index e62392f..4b18ce9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
config.ini
__pycache__
count.db
-notes.txt \ No newline at end of file
+notes.txt
+config.yaml \ No newline at end of file
diff --git a/README.md b/README.md
index 3eaa371..3011aa3 100644
--- a/README.md
+++ b/README.md
@@ -72,6 +72,8 @@ FEEDBACK_CHANNEL_ID | `CHANNEL ID`: Discord channel for feedback messages to be
BUG_CHANNEL_ID | `CHANNEL ID`: Discord channel for bug messages to be sent to | **OPTIONAL**
SPOTIFY_CLIENT_ID | Client ID from Spotify Developer account | **REQUIRED**
SPOTIFY_CLIENT_SECRET | Client Secret from Spotify Developer account | **REQUIRED**
+GENIUS_CLIENT_ID | Client ID from Genius API Dashboard | **OPTIONAL**
+GENIUS_CLIENT_SECRET | Client Secret from Genius API Dashboard | **OPTIONAL**
OPENAI_API_KEY | API Key from OpenAI for autoplay recommendations | **REQUIRED**
HOST | Host address for your Lavalink node | **REQUIRED**
PORT | Port for your Lavalink node | **REQUIRED**
diff --git a/code/bot.py b/code/bot.py
index 2864e85..3569e68 100644
--- a/code/bot.py
+++ b/code/bot.py
@@ -3,6 +3,7 @@ from discord.ext import commands, tasks
import os
import requests
import openai
+import lyricsgenius
import utils.config as config
from utils.command_tree import Tree
@@ -19,24 +20,38 @@ class MyBot(commands.Bot):
)
async def setup_hook(self):
+ # Get Spotify, Apple Music, Genius, and OpenAI access tokens/clients
get_access_token.start()
refresh_media_api_key.start()
+ login_genius.start()
+ if config.OPENAI_API_KEY:
+ bot.openai = openai.OpenAI(api_key=config.OPENAI_API_KEY)
+
config.LOG.info("Loading cogs...")
for ext in os.listdir("./code/cogs"):
if ext.endswith(".py"):
+ # Load the OPTIONAL feedback cog
if ext[:-3] == "feedback" and config.FEEDBACK_CHANNEL_ID == None:
config.LOG.info("Skipped loading feedback cog - channel ID not provided")
continue
+ # Load the OPTIONAL bug cog
if ext[:-3] == "bug" and config.BUG_CHANNEL_ID == None:
config.LOG.info("Skipped loading bug cog - channel ID not provided")
continue
+ # Load the OPTIONAL lyrics cog
+ if ext[:-3] == "lyrics" and config.GENIUS_CLIENT_ID == None:
+ config.LOG.info("Skipped loading lyrics cog - Genius API credentials not provided")
+ continue
+ # Load the OPTIONAL autoplay cog
+ if ext[:-3] == "autoplay" and config.OPENAI_API_KEY == None:
+ config.LOG.info("Skipped loading autoplay cog - OpenAI API credentials not provided")
+ continue
+
await self.load_extension(f"cogs.{ext[:-3]}")
for ext in os.listdir("./code/cogs/owner"):
if ext.endswith(".py"):
await self.load_extension(f"cogs.owner.{ext[:-3]}")
- bot.openai = openai.OpenAI(api_key=config.OPENAI_API_KEY)
-
async def on_ready(self):
config.LOG.info(f"{bot.user} has connected to Discord.")
config.LOG.info(f"Startup complete. Sync slash commands by DMing the bot {bot.command_prefix}tree sync (guild id)")
@@ -50,15 +65,19 @@ bot.autoplay = [] # guild_id, guild_id, etc.
@tasks.loop(minutes=45)
async def get_access_token():
- auth_url = "https://accounts.spotify.com/api/token"
- data = {
- "grant_type": "client_credentials",
- "client_id": config.SPOTIFY_CLIENT_ID,
- "client_secret": config.SPOTIFY_CLIENT_SECRET,
- }
- response = requests.post(auth_url, data=data)
- access_token = response.json()["access_token"]
- bot.spotify_headers = {"Authorization": f"Bearer {access_token}"}
+ if config.SPOTIFY_CLIENT_ID and config.SPOTIFY_CLIENT_SECRET:
+ auth_url = "https://accounts.spotify.com/api/token"
+ data = {
+ "grant_type": "client_credentials",
+ "client_id": config.SPOTIFY_CLIENT_ID,
+ "client_secret": config.SPOTIFY_CLIENT_SECRET,
+ }
+ response = requests.post(auth_url, data=data)
+ if response.status_code == 200:
+ access_token = response.json()["access_token"]
+ bot.spotify_headers = {"Authorization": f"Bearer {access_token}"}
+ else:
+ bot.spotify_headers = None
@tasks.loop(hours=24)
@@ -73,6 +92,24 @@ async def refresh_media_api_key():
bot.apple_headers = None
+@tasks.loop(hours=1)
+async def login_genius():
+ if config.GENIUS_CLIENT_ID and config.GENIUS_CLIENT_SECRET:
+ auth_url = "https://api.genius.com/oauth/token"
+ data = {
+ "client_id": config.GENIUS_CLIENT_ID,
+ "client_secret": config.GENIUS_CLIENT_SECRET,
+ "grant_type": "client_credentials",
+ }
+ response = requests.post(auth_url, data=data)
+ if response.status_code == 200:
+ access_token = response.json()["access_token"]
+ bot.genius = lyricsgenius.Genius(access_token)
+ bot.genius.verbose = False
+ else:
+ bot.genius = None
+
+
if __name__ == "__main__":
config.load_config()
bot.run(config.TOKEN)
diff --git a/code/cogs/help.py b/code/cogs/help.py
index 3746482..a15d6d2 100644
--- a/code/cogs/help.py
+++ b/code/cogs/help.py
@@ -88,7 +88,8 @@ commands_and_descriptions = {
class HelpView(discord.ui.View):
def __init__(self, timeout=180.0):
super().__init__(timeout=timeout)
- self.add_item(discord.ui.Button(label="Invite Me", url=BOT_INVITE_LINK, row=1))
+ if BOT_INVITE_LINK:
+ self.add_item(discord.ui.Button(label="Invite Me", url=BOT_INVITE_LINK, row=1))
@discord.ui.button(
label="View All Commands", style=discord.ButtonStyle.green, row=1
diff --git a/code/cogs/lyrics.py b/code/cogs/lyrics.py
new file mode 100644
index 0000000..711084f
--- /dev/null
+++ b/code/cogs/lyrics.py
@@ -0,0 +1,78 @@
+import discord
+import datetime
+from discord import app_commands
+from discord.ext import commands
+from cogs.music import Music
+
+from utils.config import BOT_COLOR
+
+
+class Lyrics(commands.Cog):
+ def __init__(self, bot):
+ self.bot = bot
+
+ @app_commands.command()
+ @app_commands.check(Music.create_player)
+ async def lyrics(self, interaction: discord.Interaction):
+ "Get lyrics for the song that is currently playing"
+ player = self.bot.lavalink.player_manager.get(interaction.guild.id)
+
+ # If the Genius API client is not setup, send an error message
+ if self.bot.genius is not None:
+ embed = discord.Embed(
+ title="Lyrics Feature Error",
+ description="The lyrics feature is currently disabled due to errors with the Genius API.",
+ color=BOT_COLOR,
+ )
+ embed.set_footer(
+ text=datetime.datetime.now(datetime.timezone.utc).strftime(
+ "%Y-%m-%d %H:%M:%S"
+ )
+ + " UTC"
+ )
+ return await interaction.response.send_message(embed=embed, ephemeral=True)
+
+ # Search for the songs lyrics with Genius
+ song = self.bot.genius.search_song(player.current.title, player.current.author)
+
+ # If no lyrics are found, send an error message
+ if song is None:
+ embed = discord.Embed(
+ title="Lyrics Not Found",
+ description="Unfortunately, I wasn't able to find any lyrics for the song that is currently playing.",
+ color=BOT_COLOR,
+ )
+ embed.set_thumbnail(url=player.current.artwork_url)
+ embed.set_footer(
+ text=datetime.datetime.now(datetime.timezone.utc).strftime(
+ "%Y-%m-%d %H:%M:%S"
+ )
+ + " UTC"
+ )
+
+ return await interaction.response.send_message(embed=embed, ephemeral=True)
+
+ # Remove unwanted text
+ lyrics = song.lyrics
+ lyrics = lyrics.split(" Lyrics", 1)[-1]
+ lyrics = lyrics.replace("You might also like", "\n")
+ lyrics = lyrics[:-7]
+
+ embed = discord.Embed(
+ title=f"Lyrics for {player.current.title} by {player.current.author}",
+ description=lyrics,
+ color=BOT_COLOR,
+ )
+ embed.set_thumbnail(url=player.current.artwork_url)
+ embed.set_footer(
+ text=datetime.datetime.now(datetime.timezone.utc).strftime(
+ "%Y-%m-%d %H:%M:%S"
+ )
+ + " UTC"
+ )
+
+ await interaction.response.send_message(embed=embed, ephemeral=True)
+
+
+async def setup(bot):
+ await bot.add_cog(Lyrics(bot))
diff --git a/code/cogs/play.py b/code/cogs/play.py
index db21cf7..fdd0233 100644
--- a/code/cogs/play.py
+++ b/code/cogs/play.py
@@ -147,6 +147,14 @@ class Play(commands.Cog):
###
elif "open.spotify.com" in query:
+ if not self.bot.spotify_headers:
+ embed = discord.Embed(
+ title="Spotify Error",
+ description="Spotify support seems to be broken at the moment. Please try again and fill out a bug report with </bug:1224840889906499626> if this continues to happen.",
+ color=BOT_COLOR,
+ )
+ return await interaction.response.send_message(embed=embed, ephemeral=True)
+
embed = discord.Embed(color=BOT_COLOR)
if "open.spotify.com/playlist" in query:
diff --git a/code/utils/config.py b/code/utils/config.py
index f319792..9fdcd1d 100644
--- a/code/utils/config.py
+++ b/code/utils/config.py
@@ -1,10 +1,13 @@
-import configparser
+import jsonschema
import re
import os
+import yaml
import validators
+import openai
import sys
import discord
import logging
+import requests
from colorlog import ColoredFormatter
log_level = logging.DEBUG
@@ -30,230 +33,225 @@ FEEDBACK_CHANNEL_ID = None
BUG_CHANNEL_ID = None
SPOTIFY_CLIENT_ID = None
SPOTIFY_CLIENT_SECRET = None
+GENIUS_CLIENT_ID = None
+GENIUS_CLIENT_SECRET = None
OPENAI_API_KEY = None
LAVALINK_HOST = None
LAVALINK_PORT = None
LAVALINK_PASSWORD = None
-"""
-Load the config.ini file and return the contents for validation or
-create a new templated config.ini file if it doesn't exist.
-"""
-
-
+schema = {
+ "type": "object",
+ "properties": {
+ "bot_info": {
+ "type": "object",
+ "properties": {
+ "token": {"type": "string"},
+ "bot_color": {"type": "string"},
+ "bot_invite_link": {"type": "string"},
+ "feedback_channel_id": {"type": "integer"},
+ "bug_channel_id": {"type": "integer"},
+ },
+ "required": ["token"],
+ },
+ "spotify": {
+ "type": "object",
+ "properties": {
+ "spotify_client_id": {"type": "string"},
+ "spotify_client_secret": {"type": "string"},
+ },
+ "required": ["spotify_client_id", "spotify_client_secret"],
+ },
+ "genius": {
+ "type": "object",
+ "properties": {
+ "genius_client_id": {"type": "string"},
+ "genius_client_secret": {"type": "string"},
+ },
+ "required": ["genius_client_id", "genius_client_secret"],
+ },
+ "openai": {
+ "type": "object",
+ "properties": {
+ "openai_api_key": {"type": "string"},
+ },
+ "required": ["openai_api_key"],
+ },
+ "lavalink": {
+ "type": "object",
+ "properties": {
+ "host": {"type": "string"},
+ "port": {"type": "integer"},
+ "password": {"type": "string"},
+ },
+ "required": ["host", "port", "password"],
+ },
+ },
+ "required": ["bot_info", "lavalink"],
+}
+
+
+# Attempt to load the config file, otherwise create a new template
def load_config():
- # Look for variables in the environment
- if "TOKEN" in os.environ or "BOT_COLOR" in os.environ or "BOT_INVITE_LINK" in os.environ:
- LOG.info("Detected environment variables. Checking for configuration options.")
- return validate_env_vars()
+ if os.path.exists("/.dockerenv"):
+ file_path = "/config/config.yaml"
else:
- LOG.info("Detected local environment. Checking for config.ini file.")
+ file_path = "config.yaml"
try:
- with open("config.ini", "r") as f:
+ with open(file_path, "r") as f:
file_contents = f.read()
validate_config(file_contents)
except FileNotFoundError:
- config = configparser.ConfigParser()
- config["BOT_INFO"] = {
- "TOKEN": "",
- "BOT_COLOR": "",
- "BOT_INVITE_LINK": "",
- "FEEDBACK_CHANNEL_ID": "",
- "BUG_CHANNEL_ID": "",
- }
-
- config["SPOTIFY"] = {
- "SPOTIFY_CLIENT_ID": "",
- "SPOTIFY_CLIENT_SECRET": "",
- }
-
- config["OPENAI"] = {
- "OPENAI_API_KEY": "",
- }
-
- config["LAVALINK"] = {
- "HOST": "",
- "PORT": "",
- "PASSWORD": "",
- }
-
- with open("config.ini", "w") as configfile:
- config.write(configfile)
+ # Create a new config.yaml file with the template
+ with open("config.yaml", "w") as f:
+ f.write(
+ """
+bot_info:
+ token: ""
+ bot_color: ""
+ bot_invite_link: ""
+ feedback_channel_id: ""
+ bug_channel_id: ""
+
+spotify:
+ spotify_client_id: ""
+ spotify_client_secret: ""
+
+genius:
+ genius_client_id: ""
+ genius_client_secret: ""
+
+openai:
+ openai_api_key: ""
+
+lavalink:
+ host: ""
+ port: ""
+ password: ""
+ """
+ )
sys.exit(
LOG.critical(
- "Configuration file `config.ini` has been generated. Please fill out all of the necessary information. Refer to the docs for information on what a specific configuration option is."
+ "Configuration file `config.yaml` has been generated. Please fill out all of the necessary information. Refer to the docs for information on what a specific configuration option is."
)
)
-"""
-Validate all of the options in the config.ini file.
-"""
-
-
+# Thouroughly validate all of the options in the config.yaml file
def validate_config(file_contents):
- global TOKEN, BOT_COLOR, BOT_INVITE_LINK, FEEDBACK_CHANNEL_ID, BUG_CHANNEL_ID, SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET, OPENAI_API_KEY, LAVALINK_HOST, LAVALINK_PORT, LAVALINK_PASSWORD
- config = configparser.ConfigParser()
- config.read_string(file_contents)
+ global TOKEN, BOT_COLOR, BOT_INVITE_LINK, FEEDBACK_CHANNEL_ID, BUG_CHANNEL_ID, SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET, GENIUS_CLIENT_ID, GENIUS_CLIENT_SECRET, OPENAI_API_KEY, LAVALINK_HOST, LAVALINK_PORT, LAVALINK_PASSWORD
+ config = yaml.safe_load(file_contents)
- hex_pattern_one = "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"
- hex_pattern_two = "^([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"
+ try:
+ jsonschema.validate(config, schema)
+ except jsonschema.ValidationError as e:
+ sys.exit(LOG.critical(f"Error in config.yaml file: {e.message}"))
- errors = 0
+ #
+ # Begin validation for optional BOT_INFO values
+ #
- # Make sure all sections are present
- if ["BOT_INFO", "SPOTIFY", "OPENAI", "LAVALINK"] != config.sections():
- sys.exit(
+ # If there is a "bot_invite_link" option, make sure it's a valid URL
+ if "bot_invite_link" in config["bot_info"]:
+ if not validators.url(config["bot_info"]["bot_invite_link"]):
LOG.critical(
- "Missing sections in config.ini file. Delete the file and re-run the bot to generate a blank config.ini file."
+ "Error in config.yaml file: bot_invite_link is not a valid URL"
)
- )
-
- if ["token","bot_color","bot_invite_link", "feedback_channel_id","bug_channel_id",] != config.options("BOT_INFO"):
- sys.exit(
- LOG.critical(
- "Missing options in BOT_INFO section of config.ini file. Delete the file and re-run the bot to generate a blank config.ini file."
- )
- )
+ else:
+ BOT_INVITE_LINK = config["bot_info"]["bot_invite_link"]
- if ["spotify_client_id", "spotify_client_secret"] != config.options("SPOTIFY"):
- sys.exit(
- LOG.critical(
- "Missing options in SPOTIFY section of config.ini file. Delete the file and re-run the bot to generate a blank config.ini file."
- )
- )
+ # Make sure "bot_color" is a valid hex color
+ hex_pattern_one = "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"
+ hex_pattern_two = "^([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"
- if ["openai_api_key"] != config.options("OPENAI"):
- sys.exit(
+ if "bot_color" in config["bot_info"]:
+ if not bool(
+ re.match(hex_pattern_one, config["bot_info"]["bot_color"])
+ ) and not bool(re.match(hex_pattern_two, config["bot_info"]["bot_color"])):
LOG.critical(
- "Missing options in OPENAI section of config.ini file. Delete the file and re-run the bot to generate a blank config.ini file."
+ "Error in config.yaml file: bot_color is not a valid hex color"
)
- )
-
- if ["host", "port", "password"] != config.options("LAVALINK"):
- sys.exit(
- LOG.critical(
- "Missing options in LAVALINK section of config.ini file. Delete the file and re-run the bot to generate a blank config.ini file."
- )
- )
-
- # Make sure BOT_COLOR is a valid hex color
- if not bool(re.match(hex_pattern_one, config["BOT_INFO"]["BOT_COLOR"])) and not bool(re.match(hex_pattern_two, config["BOT_INFO"]["BOT_COLOR"])):
- LOG.error("BOT_COLOR is not a valid hex color.")
- errors += 1
- else:
- BOT_COLOR = discord.Color(int((config["BOT_INFO"]["BOT_COLOR"]).replace("#", ""), 16))
-
- # Make sure BOT_INVITE_LINK is a valid URL
- if not validators.url(config["BOT_INFO"]["BOT_INVITE_LINK"]):
- LOG.error("BOT_INVITE_LINK is not a valid URL.")
- errors += 1
- else:
- BOT_INVITE_LINK = config["BOT_INFO"]["BOT_INVITE_LINK"]
-
- # Make sure FEEDBACK_CHANNEL_ID is either exactly 0 or 19 characters long
- if len(config["BOT_INFO"]["FEEDBACK_CHANNEL_ID"]) != 0:
- if len(config["BOT_INFO"]["FEEDBACK_CHANNEL_ID"]) != 19:
- LOG.error("FEEDBACK_CHANNEL_ID is not a valid Discord channel ID.")
- errors += 1
else:
- FEEDBACK_CHANNEL_ID = int(config["BOT_INFO"]["FEEDBACK_CHANNEL_ID"])
+ BOT_COLOR = discord.Color(
+ int((config["bot_info"]["bot_color"]).replace("#", ""), 16)
+ )
- # Make sure BUG_CHANNEL_ID is either exactly 0 or 19 characters long
- if len(config["BOT_INFO"]["BUG_CHANNEL_ID"]) != 0:
- if len(config["BOT_INFO"]["BUG_CHANNEL_ID"]) != 19:
- LOG.error("BUG_CHANNEL_ID is not a valid Discord channel ID.")
- errors += 1
+ # Make sure "feedback_channel_id" and "bug_channel_id" are exactly 19 characters long
+ if "feedback_channel_id" in config["bot_info"]:
+ if len(str(config["bot_info"]["feedback_channel_id"])) != 0:
+ if len(str(config["bot_info"]["feedback_channel_id"])) != 19:
+ LOG.critical(
+ "Error in config.yaml file: feedback_channel_id is not a valid Discord channel ID"
+ )
+ else:
+ FEEDBACK_CHANNEL_ID = config["bot_info"]["feedback_channel_id"]
+
+ if "bug_channel_id" in config["bot_info"]:
+ if len(str(config["bot_info"]["bug_channel_id"])) != 0:
+ if len(str(config["bot_info"]["bug_channel_id"])) != 19:
+ LOG.critical(
+ "Error in config.yaml file: bug_channel_id is not a valid Discord channel ID"
+ )
+ else:
+ BUG_CHANNEL_ID = config["bot_info"]["bug_channel_id"]
+
+ #
+ # If the SPOTIFY section is present, make sure the client ID and secret are valid
+ #
+
+ if "spotify" in config:
+ auth_url = "https://accounts.spotify.com/api/token"
+ data = {
+ "grant_type": "client_credentials",
+ "client_id": config["spotify"]["spotify_client_id"],
+ "client_secret": config["spotify"]["spotify_client_secret"],
+ }
+ response = requests.post(auth_url, data=data)
+ if response.status_code == 200:
+ SPOTIFY_CLIENT_ID = config["spotify"]["spotify_client_id"]
+ SPOTIFY_CLIENT_SECRET = config["spotify"]["spotify_client_secret"]
else:
- BUG_CHANNEL_ID = int(config["BOT_INFO"]["BUG_CHANNEL_ID"])
-
- # Assign the rest of the variables
- TOKEN = config["BOT_INFO"]["TOKEN"]
- SPOTIFY_CLIENT_ID = config["SPOTIFY"]["SPOTIFY_CLIENT_ID"]
- SPOTIFY_CLIENT_SECRET = config["SPOTIFY"]["SPOTIFY_CLIENT_SECRET"]
- OPENAI_API_KEY = config["OPENAI"]["OPENAI_API_KEY"]
- LAVALINK_HOST = config["LAVALINK"]["HOST"]
- LAVALINK_PORT = config["LAVALINK"]["PORT"]
- LAVALINK_PASSWORD = config["LAVALINK"]["PASSWORD"]
-
- if errors > 0:
- sys.exit(
LOG.critical(
- f"Found {errors} error(s) in the config.ini file. Please fix them and try again."
+ "Error in config.yaml file: Spotify client ID or secret is invalid"
)
- )
-
-
-"""
-Validate all of the environment variables.
-"""
-
-
-def validate_env_vars():
- global TOKEN, BOT_COLOR, BOT_INVITE_LINK, FEEDBACK_CHANNEL_ID, BUG_CHANNEL_ID, SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET, OPENAI_API_KEY, LAVALINK_HOST, LAVALINK_PORT, LAVALINK_PASSWORD
- hex_pattern_one = "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"
- hex_pattern_two = "^([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$"
-
- errors = 0
-
- # Make sure all required variables are present in the environment
- required_vars = ["TOKEN", "BOT_COLOR", "BOT_INVITE_LINK", "SPOTIFY_CLIENT_ID", "SPOTIFY_CLIENT_SECRET", "OPENAI_API_KEY", "LAVALINK_HOST", "LAVALINK_PORT", "LAVALINK_PASSWORD"]
-
- for var in required_vars:
- if var not in os.environ:
- LOG.error(f"Missing environment variable: {var}")
- errors += 1
-
- # Make sure BOT_COLOR is a valid hex color
- if not bool(re.match(hex_pattern_one, os.environ["BOT_COLOR"])) and not bool(re.match(hex_pattern_two, os.environ["BOT_COLOR"])):
- LOG.error("BOT_COLOR is not a valid hex color.")
- errors += 1
- else:
- BOT_COLOR = discord.Color(int((os.environ["BOT_COLOR"]).replace("#", ""), 16))
-
- # Make sure BOT_INVITE_LINK is a valid URL
- if not validators.url(os.environ["BOT_INVITE_LINK"]):
- LOG.error("BOT_INVITE_LINK is not a valid URL.")
- errors += 1
- else:
- BOT_INVITE_LINK = os.environ["BOT_INVITE_LINK"]
+ #
+ # If the GENIUS section is present, make sure the client ID and secret are valid
+ #
- # Make sure FEEDBACK_CHANNEL_ID is either None or 19 characters long
- try:
- if len(os.environ["FEEDBACK_CHANNEL_ID"]) != 19:
- LOG.error("FEEDBACK_CHANNEL_ID is not a valid Discord channel ID.")
- errors += 1
- else:
- FEEDBACK_CHANNEL_ID = int(os.environ["FEEDBACK_CHANNEL_ID"])
- except KeyError:
- FEEDBACK_CHANNEL_ID = None
-
- # Make sure BUG_CHANNEL_ID is either None or 19 characters long
- try:
- if len(os.environ["BUG_CHANNEL_ID"]) != 19:
- LOG.error("BUG_CHANNEL_ID is not a valid Discord channel ID.")
- errors += 1
+ if "genius" in config:
+ auth_url = "https://api.genius.com/oauth/token"
+ data = {
+ "grant_type": "client_credentials",
+ "client_id": config["genius"]["genius_client_id"],
+ "client_secret": config["genius"]["genius_client_secret"],
+ }
+ response = requests.post(auth_url, data=data)
+ if response.status_code == 200:
+ GENIUS_CLIENT_ID = config["genius"]["genius_client_id"]
+ GENIUS_CLIENT_SECRET = config["genius"]["genius_client_secret"]
else:
- BUG_CHANNEL_ID = int(os.environ["BUG_CHANNEL_ID"])
- except KeyError:
- BUG_CHANNEL_ID = None
-
- if errors > 0:
- sys.exit(
LOG.critical(
- f"Found {errors} error(s) with environment variables. Please fix them and try again."
+ "Error in config.yaml file: Genius client ID or secret is invalid"
)
- )
- # Assign the rest of the variables
- TOKEN = os.environ["TOKEN"]
- SPOTIFY_CLIENT_ID = os.environ["SPOTIFY_CLIENT_ID"]
- SPOTIFY_CLIENT_SECRET = os.environ["SPOTIFY_CLIENT_SECRET"]
- OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
- LAVALINK_HOST = os.environ["LAVALINK_HOST"]
- LAVALINK_PORT = os.environ["LAVALINK_PORT"]
- LAVALINK_PASSWORD = os.environ["LAVALINK_PASSWORD"] \ No newline at end of file
+ #
+ # If the OPENAI section is present, make sure the API key is valid
+ #
+
+ if "openai" in config:
+ client = openai.OpenAI(api_key=config["openai"]["openai_api_key"])
+ try:
+ client.models.list()
+ OPENAI_API_KEY = config["openai"]["openai_api_key"]
+ except openai.AuthenticationError:
+ LOG.critical("Error in config.yaml file: OpenAI API key is invalid")
+
+ # Set appropriate values for all non-optional variables
+ TOKEN = config["bot_info"]["token"]
+ LAVALINK_HOST = config["lavalink"]["host"]
+ LAVALINK_PORT = config["lavalink"]["port"]
+ LAVALINK_PASSWORD = config["lavalink"]["password"]
diff --git a/config.ini.example b/config.ini.example
deleted file mode 100644
index c2200c5..0000000
--- a/config.ini.example
+++ /dev/null
@@ -1,18 +0,0 @@
-[BOT_INFO]
-token =
-bot_color =
-bot_invite_link =
-feedback_channel_id =
-bug_channel_id =
-
-[SPOTIFY]
-spotify_client_id =
-spotify_client_secret =
-
-[OPENAI]
-openai_api_key =
-
-[LAVALINK]
-host =
-port =
-password =
diff --git a/config.yaml.example b/config.yaml.example
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/config.yaml.example
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 69953c1..8e349e8 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -2,18 +2,6 @@ services:
guava:
container_name: guava
image: ghcr.io/packetparker/guava:latest
- environment:
- - TOKEN=
- - BOT_COLOR=
- - BOT_INVITE_LINK=
- - FEEDBACK_CHANNEL_ID=
- - BUG_CHANNEL_ID=
- - SPOTIFY_CLIENT_ID=
- - SPOTIFY_CLIENT_SECRET=
- - OPENAI_API_KEY=
- - LAVALINK_HOST=
- - LAVALINK_PORT=
- - LAVALINK_PASSWORD=
volumes:
- - /path/on/system:/data
- restart: on-failure \ No newline at end of file
+ - /path/on/system:/config
+ - /path/on/system:/data \ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 265f095..293be44 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,4 +3,7 @@ lavalink==5.4.0
colorlog==6.8.2
validators==0.28.3
openai==1.35.0
-requests==2.32.3 \ No newline at end of file
+requests==2.32.3
+lyricsgenius==3.0.1
+PyYAML==6.0.1
+jsonschema==4.23.0 \ No newline at end of file