Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wip: Joyboard Port to Main #267

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
59 changes: 43 additions & 16 deletions chiya/cogs/listeners/joyboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,18 @@


class Joyboard(commands.Cog):

JOYS = ("😂", "😹", "joy_pride", "joy_tone1", "joy_tone5", "joy_logga")

def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
self.cache = {"add": set(), "remove": set()}

def generate_color(self, joy_count: int) -> int:
"""
Hue, saturation, and value is divided by 360, 100, 100 respectively because it is using the fourth coordinate group
described in https://en.wikipedia.org/wiki/Wikipedia:WikiProject_Color/Normalized_Color_Coordinates#HSV_coordinates.
Hue, saturation, and value is divided by 360, 100, 100 respectively because it is using the
fourth coordinate group described in
https://en.wikipedia.org/wiki/Wikipedia:WikiProject_Color/Normalized_Color_Coordinates#HSV_coordinates.
"""
if joy_count <= 5:
saturation = 0.4
Expand All @@ -32,10 +36,10 @@ def generate_color(self, joy_count: int) -> int:

return discord.Color.from_hsv(48 / 360, saturation, 1).value

async def get_joy_count(self, message: discord.Message, joys: tuple) -> int:
async def get_joy_count(self, message: discord.Message) -> int:
unique_users = set()
for reaction in message.reactions:
if reaction.emoji not in joys:
if not self.check_emoji(reaction.emoji, message.guild.id):
continue

async for user in reaction.users():
Expand All @@ -44,6 +48,25 @@ async def get_joy_count(self, message: discord.Message, joys: tuple) -> int:

return len(unique_users)

def check_emoji(self, emoji: discord.PartialEmoji | discord.Emoji, guild_id: int):
if isinstance(emoji, discord.PartialEmoji) and emoji.is_custom_emoji():
guild = self.bot.get_guild(guild_id)
if not guild:
return False

global_emoji = discord.utils.get(guild.emojis, id=emoji.id)
if not global_emoji:
return False
elif isinstance(emoji, discord.Emoji):
if emoji.guild_id is None:
return False

if emoji.guild_id != guild_id:
return False

name = emoji if isinstance(emoji, str) else emoji.name
return name in self.JOYS or name.startswith("joy_")

@commands.Cog.listener()
async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent) -> None:
"""
Expand All @@ -53,28 +76,33 @@ async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent) ->
Implements a cache to prevent race condition where if multiple joys were reacted on a message after it hits the
joy threshold and the IDs were not written to the database quickly enough, a duplicated joy embed would be sent.
"""
joys = ("😂",)
if payload.emoji.name not in joys:
cache_data = (payload.message_id, payload.channel_id)

if (
not self.check_emoji(payload.emoji, payload.guild_id)
or cache_data in self.cache["add"]
):
return

channel = self.bot.get_channel(payload.channel_id)
message = await channel.fetch_message(payload.message_id)
joy_count = await self.get_joy_count(message, joys)
cache_data = (payload.message_id, payload.channel_id)
joy_count = await self.get_joy_count(message)

if (
message.author.bot
or message.author.id == payload.member.id
or channel.is_nsfw()
or payload.channel_id in config["channels"]["joyboard"]["blacklisted"]
or joy_count < config["channels"]["joyboard"]["joy_limit"]
or cache_data in self.cache["add"]
):
return

self.cache["add"].add(cache_data)

joyboard_channel = discord.utils.get(message.guild.channels, id=config["channels"]["joyboard"]["channel_id"])
joyboard_channel = discord.utils.get(
message.guild.channels,
id=config["channels"]["joyboard"]["channel_id"]
)

db = database.Database().get()
result = db["joyboard"].find_one(channel_id=payload.channel_id, message_id=payload.message_id)
Expand All @@ -85,12 +113,12 @@ async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent) ->
embed_dict = joy_embed.embeds[0].to_dict()
embed_dict["color"] = self.generate_color(joy_count=joy_count)
embed = discord.Embed.from_dict(embed_dict)
self.cache["add"].remove(cache_data)
await joy_embed.edit(
content=f"😂 **{joy_count}** {message.channel.mention}",
embed=embed,
)
return db.close()
db.close()
return
# Joy embed found in database but the actual joy embed was deleted.
except discord.NotFound:
pass
Expand Down Expand Up @@ -154,13 +182,12 @@ async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent) ->
@commands.Cog.listener()
async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent) -> None:
"""
Update the joy count in the embed if the joys were reacted. Delete joy embed if the joy count is below threshold.
Update the joy count in the embed if the joys were reacted. Delete joy embed if the joy count is below threshold
"""
joys = ("😂",)
cache_data = (payload.message_id, payload.channel_id)

if (
payload.emoji.name not in joys
not self.check_emoji(payload.emoji, payload.guild_id)
or cache_data in self.cache["remove"]
):
return
Expand All @@ -184,7 +211,7 @@ async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent)
self.cache["remove"].remove(cache_data)
return db.close()

joy_count = await self.get_joy_count(message, joys)
joy_count = await self.get_joy_count(message)

if joy_count < config["channels"]["joyboard"]["joy_limit"]:
db["joyboard"].delete(channel_id=payload.channel_id, message_id=payload.message_id)
Expand Down