Initial commit, already feature complete.
This commit is contained in:
commit
af0d6cd2c0
7 changed files with 256 additions and 0 deletions
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Ignore python cache
|
||||
**/*.pyc
|
||||
**/__pycache__/*
|
||||
|
||||
# Ignore python virtual environment
|
||||
.venv/
|
||||
|
||||
# Ignore log files
|
||||
**/*.log
|
||||
|
||||
# Ignore config file
|
||||
**/config.json
|
1
.python-version
Normal file
1
.python-version
Normal file
|
@ -0,0 +1 @@
|
|||
3.11
|
57
README.md
Normal file
57
README.md
Normal file
|
@ -0,0 +1,57 @@
|
|||
# Discord emoji uploader
|
||||
|
||||
I just wanna put my emojis on my Discord server.
|
||||
|
||||
## Setup
|
||||
|
||||
### (Optional) Set up a virtual environment
|
||||
|
||||
```
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
```
|
||||
|
||||
### Install the required packages
|
||||
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### Edit the config
|
||||
|
||||
Rename `sample-config.json` to `config.json`.
|
||||
|
||||
```
|
||||
mv sample-config.json config.json
|
||||
```
|
||||
|
||||
Then, edit in your API Key and Guild ID.
|
||||
|
||||
### (Optional) Add emoji files
|
||||
|
||||
Any images in the `emojis/` directory will be uploaded by default.
|
||||
|
||||
## Usage
|
||||
|
||||
Assuming your `config.json` is in the default place at the root of the
|
||||
project directory, and the emoji images you want to upload are in `emoji/`,
|
||||
you do not need to add any arguments. You can, however, run
|
||||
`upload-emoji.py -h` for a usage printout.
|
||||
|
||||
You can specify a config file with `-c`.
|
||||
|
||||
```
|
||||
upload-emoji.py -c some/path/to/config.json
|
||||
```
|
||||
|
||||
You can also specify a directory for emojis.
|
||||
|
||||
```
|
||||
upload-emoji.py -e some/path/to/emoji/images/
|
||||
```
|
||||
|
||||
If you want more verbose logs, you can use the `-v` flag.
|
||||
|
||||
```
|
||||
upload-emoji.py -v
|
||||
```
|
0
emojis/.gitkeep
Normal file
0
emojis/.gitkeep
Normal file
11
requirements.txt
Normal file
11
requirements.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
aiohappyeyeballs==2.6.1
|
||||
aiohttp==3.11.16
|
||||
aiosignal==1.3.2
|
||||
attrs==25.3.0
|
||||
discord==2.3.2
|
||||
discord.py==2.5.2
|
||||
frozenlist==1.5.0
|
||||
idna==3.10
|
||||
multidict==6.2.0
|
||||
propcache==0.3.1
|
||||
yarl==1.19.0
|
4
sample-config.json
Normal file
4
sample-config.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"api_key": "(Your big api_key from https://discord.com/developers)",
|
||||
"guild_id": "0000000000000000000"
|
||||
}
|
171
upload-emoji.py
Executable file
171
upload-emoji.py
Executable file
|
@ -0,0 +1,171 @@
|
|||
#!/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()
|
Loading…
Reference in a new issue