Skip to content

Commit

Permalink
Custom Emoji Support (#5)
Browse files Browse the repository at this point in the history
* Changes to support custom emoji. Almost complete.

* Can add custom emojis in config. Added comments.

* Added configuration example to readme
  • Loading branch information
rsoper authored May 5, 2021
1 parent d6c62d9 commit b26b3f9
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 46 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,23 @@ From the root of this repository simply put the Discord token and your desired c

```
docker-compose up -d
```

# Configuration

This configuration method is not ideal. I will be adding a flask based web UI in the future to allow for more simplistic configuration. For now all config will take place in a json file.

```json
{
"roles": [
{
"react": ":money_with_wings:", // Enter the name of the emoji here.
"react_id": 0, // Leave this at 0 on first run. It will be updated as needed.
"role": "Inventory Hunter", // Enter the exact spelling of the role to apply for the emoji
"description": "if you want notifications from Inventory Hunter", // Enter a description of the role.
"role_id": 0 // Leave this at 0 on first run. It will be updated as needed.
}
],
"role_message_id": 0 // Leave this at 0 on first run. It will be updated as needed.
}
```
14 changes: 13 additions & 1 deletion bot/config/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,84 @@
"roles": [
{
"react": ":money_with_wings:",
"react_id": 0,
"role": "Inventory Hunter",
"description": "if you want notifications from Inventory Hunter",
"role_id": 0
},
{
"react": ":axe:",
"react": ":valheim:",
"react_id": 0,
"role": "Valheim",
"description": "if you want to play Valheim",
"role_id": 0
},
{
"react": ":musical_note:",
"react_id": 0,
"role": "Music Control",
"description": "if you'd like to control the Groovy bot",
"role_id": 0
},
{
"react": ":military_helmet:",
"react_id": 0,
"role": "Siege",
"description": "if you want to play Rainbow 6 Siege",
"role_id": 0
},
{
"react": ":radioactive:",
"react_id": 0,
"role": "Rust",
"description": "if you want to play Rust",
"role_id": 0
},
{
"react": ":warning:",
"react_id": 0,
"role": "Tarkov",
"description": "if you want to play Escape From Tarkov",
"role_id": 0
},
{
"react": ":military_medal:",
"react_id": 0,
"role": "Insurgency",
"description": "if you want to play Insurgency",
"role_id": 0
},
{
"react": ":robot:",
"react_id": 0,
"role": "Satisfactory",
"description": "if you want to play Satisfactory",
"role_id": 0
},
{
"react": ":keyboard:",
"react_id": 0,
"role": "Code",
"description": "if you want to talk about code",
"role_id": 0
},
{
"react": ":desktop_computer:",
"react_id": 0,
"role": "Hardware",
"description": "if you want to talk about gear/hardware",
"role_id": 0
},
{
"react": ":control_knobs:",
"react_id": 0,
"role": "Self Hosted",
"description": "if you want to talk about self hosted apps",
"role_id": 0
},
{
"react": ":dna:",
"react_id": 0,
"role": "Outriders",
"description": "if you want to play Outriders",
"role_id": 0
Expand Down
158 changes: 113 additions & 45 deletions bot/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,64 @@
os.path.dirname(__file__), "config/config.json")


def interpret_emoji(payload):
"""
Handle logic from both add/remove emoji reacts here. DRY you idiot.
"""
if payload.emoji.is_custom_emoji():
emoji_name = f":{payload.emoji.name}:"
else:
emoji_name = emoji.demojize(payload.emoji.name)

role_ID = get_role_ID(emoji_name)

for role in roles:
if role_ID == role.id:
return role

return None


def eligible_for_action(payload):
user = client.get_user(payload.user_id)
# If the user reacting is the bot, return
if user == client.user:
return False
# If the reaction is not on the correct message for manging roles, return.
# Defined in config/config.json
if get_message_id() != payload.message_id:
return False
return True


def map_emoji_ids():
"""
Match Emoji ID's from the server with emojis in the config
"""
with open(configFileLocation, "r") as settingsFile:
settingsData = json.load(settingsFile)
configuredRoles = settingsData["roles"]

for item in configuredRoles:
if item["react_id"] == 0:
for custom_emoji in client.emojis:
if custom_emoji.name in item["react"]:
item["react_id"] = custom_emoji.id
else:
continue

settingsData["roles"] = configuredRoles

with open(configFileLocation, "w") as configFile:
json.dump(settingsData, configFile, indent=4)


def role_message_exists():
"""
Determine if a role message has been saved to the config
Return Bool
"""
with open(configFileLocation, "r") as configFile:
configData = json.load(configFile)
message_id = configData["role_message_id"]
Expand All @@ -23,6 +80,11 @@ def role_message_exists():


def get_message_id():
"""
Retreive the message ID saved in the config file
Return Int(message_id)
"""
with open(configFileLocation, "r") as configFile:
configData = json.load(configFile)
message_id = configData["role_message_id"]
Expand All @@ -35,7 +97,7 @@ def store_message_id(message_id):

configData["role_message_id"] = message_id
with open(configFileLocation, "w") as configFile:
json.dump(configData, configFile)
json.dump(configData, configFile, indent=4)


def get_role_ID(react):
Expand All @@ -49,6 +111,11 @@ def get_role_ID(react):


def map_role_ID(roles):
"""
Match Role ID's from the server with Role names in the config
roles = [Role objects]
"""
with open(configFileLocation, "r") as settingsFile:
settingsData = json.load(settingsFile)
configuredRoles = settingsData["roles"]
Expand All @@ -64,10 +131,16 @@ def map_role_ID(roles):
settingsData["roles"] = configuredRoles

with open(configFileLocation, "w") as configFile:
json.dump(settingsData, configFile)
json.dump(settingsData, configFile, indent=4)


def build_message():
"""
Build the multi-line message combining reactions and descriptions
from the config.
Return str(finalMessage)
"""
finalMessage = """\n"""
messageLines = []
with open(configFileLocation) as settingsFile:
Expand All @@ -76,90 +149,85 @@ def build_message():

for item in configuredRoles:
react = item["react"]
for custom_emoji in client.emojis:
if custom_emoji.name in react:
react = f"<{item['react']}{item['react_id']}>"
roleDescription = item["description"]
messageLines.append(f"React {react} {roleDescription}")

return finalMessage.join(messageLines)


def get_all_reacts():
"""
Get all the reaction names from the config file
Return [reacts]
"""
reacts = []
with open(configFileLocation) as settingsFile:
settingsData = json.load(settingsFile)
configuredRoles = settingsData["roles"]

for item in configuredRoles:
reacts.append(item["react"])
if item["react_id"] != 0:
reacts.append(f"<{item['react']}{item['react_id']}>")
else:
reacts.append(item["react"])

return reacts


@client.event
async def on_raw_reaction_add(payload):
# Get user details
user = client.get_user(payload.user_id)
# If the user reacting is the bot, return
if user == client.user:
return
# If the reaction is not on the correct message for manging roles, return.
# Defined in config/config.json
if get_message_id() != payload.message_id:
return
role_ID = get_role_ID(emoji.demojize(str(payload.emoji)))
for role in roles:
if role_ID == role.id:
await payload.member.add_roles(role)
print(
f"The user {payload.member} was added to the role {role.name}")
if eligible_for_action(payload):
role = interpret_emoji(payload)
if role == None:
return
await payload.member.add_roles(role)
print(
f"The user {payload.member} was added to the role {role.name}")


@client.event
async def on_raw_reaction_remove(payload):
# Get user details
user = client.get_user(payload.user_id)
# If the user reacting is the bot, return
if user == client.user:
return
# If the reaction is not on the correct message for manging roles, return.
# Defined in config/config.json
if get_message_id() != payload.message_id:
return
# Cycle through roles and find the role matching the reaction
role_ID = get_role_ID(emoji.demojize(str(payload.emoji)))
for role in roles:
if role_ID == role.id:
user = client.get_user(payload.user_id)
for member in client.get_all_members():
if member.id == payload.user_id:
user = member
await user.remove_roles(role)
print(
f"The user {user.name} was removed from the role {role.name}")
if eligible_for_action(payload):
role = interpret_emoji(payload)
if role == None:
return
for member in client.get_all_members():
if member.id == payload.user_id:
user = member
await user.remove_roles(role)
print(
f"The user {user.name} was removed from the role {role.name}")


@client.event
async def on_ready():
global roles, roleMessage
print(f"{client.user} has connected to Discord!")
# Set bot status in the server
await client.change_presence(activity=botActivity)
channel = await client.fetch_channel(channel_id=CHANNEL_ID)
roles = await client.guilds[0].fetch_roles()
map_role_ID(roles)
map_emoji_ids()

if role_message_exists():
print("Role message exists already. Thanks!")
roleMessage = await channel.fetch_message(get_message_id())
await roleMessage.edit(content=build_message())
else:
roleMessage = await channel.send(content=build_message())
store_message_id(roleMessage.id)

default_reacts = get_all_reacts()
# Remove all reactions from the bot on the message.
for react in roleMessage.reactions:
await react.remove(client.user)

# Add a reaction from the bot for each in the config
default_reacts = get_all_reacts()
for react in default_reacts:
print(f"Adding {emoji.emojize(react, use_aliases=True)}")
await roleMessage.add_reaction(emoji.emojize(react, use_aliases=True))

roles = await client.guilds[0].fetch_roles()
map_role_ID(roles)


client.run(TOKEN)

0 comments on commit b26b3f9

Please sign in to comment.