2022-11-30 21:01:16 +00:00
|
|
|
import asyncio
|
2023-05-01 18:49:23 +01:00
|
|
|
import io
|
2023-11-04 17:18:39 +00:00
|
|
|
import textwrap
|
2022-11-30 21:01:16 +00:00
|
|
|
from typing import Tuple
|
2023-11-04 17:18:39 +00:00
|
|
|
from urllib.parse import urlparse
|
2022-11-30 21:01:16 +00:00
|
|
|
|
|
|
|
import discord
|
2023-11-04 17:18:39 +00:00
|
|
|
import httpx
|
2023-05-04 18:12:39 +01:00
|
|
|
import orm
|
2022-11-30 21:01:16 +00:00
|
|
|
from discord.ext import commands
|
2023-11-04 17:18:39 +00:00
|
|
|
|
2022-11-30 21:01:16 +00:00
|
|
|
from utils.db import StarBoardMessage
|
|
|
|
|
|
|
|
|
|
|
|
class StarBoardCog(commands.Cog):
|
|
|
|
def __init__(self, bot):
|
|
|
|
self.bot = bot
|
|
|
|
self.lock = asyncio.Lock()
|
|
|
|
|
2023-05-01 18:49:23 +01:00
|
|
|
@staticmethod
|
2023-05-04 11:37:48 +01:00
|
|
|
async def archive_image(starboard_message: discord.Message):
|
2023-05-01 18:49:23 +01:00
|
|
|
async with httpx.AsyncClient(
|
|
|
|
headers={
|
|
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.69; Win64; x64) "
|
2023-11-24 17:39:17 +00:00
|
|
|
"LCC-Bot-Scraper/0 (https://github.com/nexy7574/LCC-bot)"
|
2023-05-01 18:49:23 +01:00
|
|
|
}
|
|
|
|
) as session:
|
|
|
|
image = starboard_message.embeds[0].image
|
|
|
|
if image and image.url:
|
|
|
|
parsed = urlparse(image.url)
|
|
|
|
filename = parsed.path.split("/")[-1]
|
|
|
|
try:
|
|
|
|
r = await session.get(image.url)
|
|
|
|
except httpx.HTTPError:
|
|
|
|
if image.proxy_url:
|
|
|
|
r = await session.get(image.proxy_url)
|
|
|
|
else:
|
|
|
|
return
|
|
|
|
|
|
|
|
FS_LIMIT = starboard_message.guild.filesize_limit
|
|
|
|
# if FS_LIMIT is 8mb, its actually 25MB
|
|
|
|
if FS_LIMIT == 8 * 1024 * 1024:
|
|
|
|
FS_LIMIT = 25 * 1024 * 1024
|
|
|
|
if r.status_code == 200 and len(r.content) < FS_LIMIT:
|
|
|
|
file = io.BytesIO(r.content)
|
|
|
|
file.seek(0)
|
|
|
|
embed = starboard_message.embeds[0].copy()
|
|
|
|
embed.set_image(url="attachment://" + filename)
|
2023-11-04 17:18:39 +00:00
|
|
|
embeds = [embed, *starboard_message.embeds[1:]]
|
2023-05-04 18:06:17 +01:00
|
|
|
await starboard_message.edit(embeds=embeds, file=discord.File(file, filename=filename))
|
2023-05-01 18:49:23 +01:00
|
|
|
|
2022-11-30 21:01:16 +00:00
|
|
|
async def generate_starboard_embed(self, message: discord.Message) -> discord.Embed:
|
|
|
|
star_count = [x for x in message.reactions if str(x.emoji) == "\N{white medium star}"]
|
|
|
|
if not star_count:
|
|
|
|
star_count = 0
|
|
|
|
else:
|
|
|
|
star_count = star_count[0].count
|
|
|
|
embed = discord.Embed(colour=discord.Colour.gold(), timestamp=message.created_at, description=message.content)
|
|
|
|
embed.set_author(
|
|
|
|
name=message.author.display_name, url=message.jump_url, icon_url=message.author.display_avatar.url
|
|
|
|
)
|
|
|
|
|
|
|
|
if star_count > 5:
|
|
|
|
stars = "\N{white medium star}x{:,}".format(star_count)
|
|
|
|
else:
|
|
|
|
stars = "\N{white medium star}" * star_count
|
|
|
|
stars = stars or "\N{no entry sign}"
|
|
|
|
|
|
|
|
embed.add_field(
|
|
|
|
name="Info",
|
|
|
|
value=f"Star count: {stars}\n"
|
|
|
|
f"Channel: {message.channel.mention}\n"
|
|
|
|
f"Author: {message.author.mention}\n"
|
|
|
|
f"URL: [jump]({message.jump_url})\n"
|
|
|
|
f"Sent: {discord.utils.format_dt(message.created_at, 'R')}",
|
|
|
|
inline=False,
|
|
|
|
)
|
|
|
|
if message.edited_at:
|
|
|
|
embed.fields[0].value += "\nLast edited: " + discord.utils.format_dt(message.edited_at, "R")
|
|
|
|
|
|
|
|
if message.reference is not None:
|
|
|
|
try:
|
|
|
|
ref: discord.Message = await self.bot.get_channel(message.reference.channel_id).fetch_message(
|
|
|
|
message.reference.message_id
|
|
|
|
)
|
|
|
|
except discord.HTTPException:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
embed.add_field(
|
|
|
|
name="In reply to",
|
|
|
|
value=f"[Message by {ref.author.display_name}]({ref.jump_url}):\n>>> ",
|
|
|
|
inline=False,
|
|
|
|
)
|
|
|
|
field = embed.fields[1]
|
|
|
|
if not ref.content:
|
|
|
|
embed.fields[1].value = field.value.replace(":\n>>> ", "")
|
|
|
|
else:
|
|
|
|
embed.fields[1].value += textwrap.shorten(ref.content, 1024 - len(field.value), placeholder="...")
|
2023-11-24 17:57:06 +00:00
|
|
|
if message.interaction is not None:
|
2023-11-24 17:49:26 +00:00
|
|
|
inter: discord.MessageInteraction = message.interaction
|
2023-11-24 17:57:06 +00:00
|
|
|
if inter.type == discord.InteractionType.application_command:
|
|
|
|
cmd = "</{}:{}>".format(inter.id, inter.name)
|
|
|
|
else:
|
|
|
|
cmd = repr(inter.name)
|
2023-11-24 17:49:26 +00:00
|
|
|
embed.add_field(
|
|
|
|
name="In response to",
|
2023-11-24 17:57:06 +00:00
|
|
|
value=f"Command {cmd} by {inter.user.display_name}",
|
2023-11-24 17:49:26 +00:00
|
|
|
inline=False,
|
|
|
|
)
|
2022-11-30 21:01:16 +00:00
|
|
|
|
2023-11-24 17:42:01 +00:00
|
|
|
for file in message.attachments:
|
|
|
|
name = f"Attachment #{message.attachments.index(file)}"
|
|
|
|
spoiler = file.is_spoiler()
|
|
|
|
if spoiler:
|
|
|
|
embed.add_field(name=name, value=f"||[{file.filename}]({file.url})||", inline=False)
|
|
|
|
else:
|
|
|
|
if file.content_type.startswith("image"):
|
|
|
|
if embed.image.url is discord.Embed.Empty:
|
2023-11-24 17:39:17 +00:00
|
|
|
embed.set_image(url=file.url)
|
2023-11-24 17:42:01 +00:00
|
|
|
embed.add_field(name=name, value=f"[{file.filename}]({file.url})", inline=False)
|
2022-11-30 21:01:16 +00:00
|
|
|
|
2023-11-24 17:39:17 +00:00
|
|
|
# embed.set_footer(text="Starboard threshold for this message was {:.2f}.".format(cap))
|
2022-11-30 21:01:16 +00:00
|
|
|
return embed
|
|
|
|
|
|
|
|
@commands.Cog.listener("on_raw_reaction_add")
|
|
|
|
@commands.Cog.listener("on_raw_reaction_remove")
|
|
|
|
async def on_star_add(self, payload: discord.RawReactionActionEvent):
|
2023-01-25 15:22:17 +00:00
|
|
|
if not payload.guild_id:
|
|
|
|
return
|
2022-11-30 21:01:16 +00:00
|
|
|
async with self.lock:
|
|
|
|
if str(payload.emoji) != "\N{white medium star}":
|
|
|
|
return
|
|
|
|
message: discord.Message = await self.bot.get_channel(payload.channel_id).fetch_message(payload.message_id)
|
2023-01-25 15:22:17 +00:00
|
|
|
if message.author.id == payload.user_id and payload.event_type == "REACTION_ADD":
|
|
|
|
if message.channel.permissions_for(message.guild.me).manage_messages:
|
|
|
|
await message.remove_reaction(payload.emoji, message.author)
|
|
|
|
return await message.reply(
|
|
|
|
f"You can't star your own messages you pretentious dick, {message.author.mention}."
|
|
|
|
)
|
2022-11-30 21:01:16 +00:00
|
|
|
star_count = [x for x in message.reactions if str(x.emoji) == "\N{white medium star}"]
|
|
|
|
if not star_count:
|
|
|
|
star_count = 0
|
|
|
|
else:
|
|
|
|
star_count = star_count[0].count
|
2023-05-04 18:12:39 +01:00
|
|
|
|
|
|
|
if star_count == 0:
|
|
|
|
try:
|
|
|
|
database: StarBoardMessage = await StarBoardMessage.objects.get(id=payload.message_id)
|
|
|
|
except orm.NoMatch:
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
channel = discord.utils.get(message.guild.text_channels, name="starboard")
|
|
|
|
if channel:
|
|
|
|
try:
|
|
|
|
message = await channel.fetch_message(database.id)
|
|
|
|
await message.delete(delay=0.1, reason="Starboard message lost all stars.")
|
|
|
|
except discord.HTTPException:
|
|
|
|
pass
|
|
|
|
finally:
|
|
|
|
await database.delete()
|
|
|
|
else:
|
|
|
|
await database.delete()
|
|
|
|
|
2022-11-30 21:01:16 +00:00
|
|
|
database: Tuple[StarBoardMessage, bool] = await StarBoardMessage.objects.get_or_create(
|
|
|
|
{"channel": payload.channel_id}, id=payload.message_id
|
|
|
|
)
|
|
|
|
entry, created = database
|
|
|
|
if created:
|
|
|
|
# noinspection PyUnresolvedReferences
|
2022-11-30 21:10:24 +00:00
|
|
|
cap = message.channel
|
2022-11-30 21:01:16 +00:00
|
|
|
if self.bot.intents.members and hasattr(cap, "members"):
|
|
|
|
cap = len([x for x in cap.members if not x.bot]) * 0.1
|
|
|
|
else:
|
|
|
|
cap = cap.member_count * 0.1
|
|
|
|
if star_count >= cap:
|
|
|
|
channel = discord.utils.get(message.guild.text_channels, name="starboard")
|
|
|
|
if channel and channel.can_send():
|
2023-05-04 11:37:48 +01:00
|
|
|
embed = await self.generate_starboard_embed(message)
|
|
|
|
embeds = [embed, *tuple(filter(lambda x: x.type == "rich", message.embeds))][:10]
|
|
|
|
msg = await channel.send(embeds=embeds)
|
2022-11-30 21:01:16 +00:00
|
|
|
await entry.update(starboard_message=msg.id)
|
2023-05-01 18:49:23 +01:00
|
|
|
self.bot.loop.create_task(self.archive_image(msg))
|
2022-11-30 21:01:16 +00:00
|
|
|
else:
|
|
|
|
await entry.delete()
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
channel = discord.utils.get(message.guild.text_channels, name="starboard")
|
2023-04-28 15:05:40 +01:00
|
|
|
embed = await self.generate_starboard_embed(message)
|
|
|
|
embeds = [embed, *tuple(filter(lambda x: x.type == "rich", message.embeds))][:10]
|
2022-11-30 21:01:16 +00:00
|
|
|
if channel and channel.can_send() and entry.starboard_message:
|
|
|
|
try:
|
|
|
|
msg = await channel.fetch_message(entry.starboard_message)
|
|
|
|
except discord.NotFound:
|
2023-04-28 15:05:40 +01:00
|
|
|
msg = await channel.send(embeds=embeds)
|
2022-11-30 21:01:16 +00:00
|
|
|
await entry.update(starboard_message=msg.id)
|
2023-05-01 18:49:23 +01:00
|
|
|
self.bot.loop.create_task(self.archive_image(msg))
|
2022-11-30 21:01:16 +00:00
|
|
|
except discord.HTTPException:
|
|
|
|
pass
|
|
|
|
else:
|
2023-04-28 15:05:40 +01:00
|
|
|
await msg.edit(embeds=embeds)
|
2023-05-01 18:49:23 +01:00
|
|
|
self.bot.loop.create_task(self.archive_image(msg))
|
2022-11-30 21:01:16 +00:00
|
|
|
|
|
|
|
@commands.message_command(name="Starboard Info")
|
|
|
|
@discord.guild_only()
|
|
|
|
async def get_starboard_info(self, ctx: discord.ApplicationContext, message: discord.Message):
|
|
|
|
return await ctx.respond(embed=await self.generate_starboard_embed(message))
|
|
|
|
|
|
|
|
|
|
|
|
def setup(bot):
|
|
|
|
bot.add_cog(StarBoardCog(bot))
|