discord-emoji-uploader/upload-emoji.py

171 lines
4.8 KiB
Python
Executable file

#!/usr/bin/env python
from argparse import ArgumentParser, Namespace
from json import load
from pathlib import Path
from logging import error, info, debug, INFO, DEBUG, FileHandler
from sys import exit
from os import listdir
from os.path import splitext
from discord import Client, Intents
# Set default paths for config and emoji dir, and supported file formats
DEFAULT_CONFIG_PATH = "config.json"
DEFAULT_EMOJI_DIR = "emojis/"
SUPPORTED_FORMATS = [".jpeg", ".jpg", ".png", ".gif"]
class EmojiUploadClient(Client):
emoji_dir: Path = Path("")
guild_id: str = ""
async def on_ready(self):
"""Key function to run upon startup."""
info(f"Logged on as {self.user}")
# Attempt to upload emoji after startup.
await self.upload_emoji()
async def upload_emoji(self):
"""Uses emoji_dir and guild_id to upload all emoji in the directory
to the specified guild.
"""
info(f'Attempting to upload emoji at "{self.emoji_dir}"...')
# Check guild_id is numeric.
if not self.guild_id.isnumeric():
error(f"Not a proper guild_id: {self.guild_id}")
exit(1)
# Obtain guild object.
guild = self.get_guild(int(self.guild_id))
# Grab list of emoji files.
emoji_files = listdir(self.emoji_dir)
# Iterate through emojis and attempt to upload them.
for emoji in emoji_files:
current_emoji_filepath = f"{self.emoji_dir}/{emoji}"
(file_name, file_extension) = splitext(emoji)
# Validate that the image is a supported format.
if file_extension not in SUPPORTED_FORMATS:
debug(f'Skipping: "{current_emoji_filepath}"')
continue
# Try to upload the custom emoji.
debug(f"Attempting to upload: {current_emoji_filepath}")
with open(current_emoji_filepath, "rb") as img:
await guild.create_custom_emoji(name=file_name, image=img.read())
# Disconnect the client.
info("All emojis attempted, disconnecting.")
await self.close()
def parse_config(config_file: Path) -> tuple:
try:
with open(config_file) as config:
parse_config = load(config)
return (parse_config["api_key"], parse_config["guild_id"])
except Exception:
error(f"There was an error parsing the config file at: {config_file}")
exit(1)
return
def parse_opts(opts: Namespace) -> tuple:
"""Parse out opts for config and emoji paths.
Args:
opts (Namespace): Opts object to be parsed.
Returns:
(config_path, emoji_dir): Tuple of opts paths parsed.
"""
try:
info(
f"""
config_file: {opts.config_file}
emoji_dir: {opts.emoji_dir}
"""
)
config_file = Path(opts.config_file)
emoji_dir = Path(opts.emoji_dir)
except Exception:
error(f"{Exception}\nCould not successfully parse arguments.")
exit(1)
if not config_file.exists():
error(f'No config file found at "{config_file}".')
exit(1)
if not emoji_dir.exists():
error(f'"{emoji_dir}" is not a valid directory.')
exit(1)
if opts.verbose:
log_level = DEBUG
else:
log_level = INFO
return (config_file, emoji_dir, log_level)
def make_args() -> ArgumentParser:
"""Create an ArgumentParser object.
Returns:
ArgumentParser: ArgumentParser object
"""
parser = ArgumentParser()
parser.add_argument(
"-c",
"--config-file",
default=DEFAULT_CONFIG_PATH,
help=f"Path to config json, defaults to: {DEFAULT_CONFIG_PATH}",
)
parser.add_argument(
"-e",
"--emoji-dir",
default=DEFAULT_EMOJI_DIR,
help=f"Path to emoji directory, defaults to: {DEFAULT_EMOJI_DIR}",
)
parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="Sets the logging level to DEBUG.",
)
return parser
def main(argv: list[str] | None = None, print_stdout: bool | None = True):
args = make_args()
opts = args.parse_args(argv)
# Parse out the config filepath, emoji directory, and verbose flag.
config_file, emoji_dir, log_level = parse_opts(opts)
# Parse out the api key and the guild id.
(api_key, guild_id) = parse_config(config_file)
# Create Discord API Client object and set properties.
client = EmojiUploadClient(intents=Intents.default())
client.emoji_dir = emoji_dir
client.guild_id = guild_id
# Set up logging for Discord API Client
handler = FileHandler(filename="emoji_uploader.log", encoding="utf-8", mode="w")
# Run the Discord API Client.
client.run(api_key, log_handler=handler, root_logger=True, log_level=log_level)
exit(0)
if __name__ == "__main__":
main()