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

リアクションを押して展開されたメッセージを消去する機能の追加 #24

Merged
merged 8 commits into from
Jun 20, 2021
112 changes: 109 additions & 3 deletions dispander/module.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import discord
from discord import Embed
from discord.embeds import EmptyEmbed
from discord.ext import commands
import re

regex_discord_message_url = (
'(?!<)https://(ptb.|canary.)?discord(app)?.com/channels/'
'(?P<guild>[0-9]{18})/(?P<channel>[0-9]{18})/(?P<message>[0-9]{18})(?!>)'
)
regex_extra_url = (
r'\?base_aid=(?P<base_author_id>[0-9]{18})'
'&aid=(?P<author_id>[0-9]{18})'
'&extra=(?P<extra_messages>[0-9,]+)'
)
DELETE_REACTION_EMOJI = "\U0001f5d1"


class ExpandDiscordMessageUrl(commands.Cog):
Expand All @@ -18,21 +26,85 @@ async def on_message(self, message):
return
await dispand(message)

@commands.Cog.listener()
async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent):
await delete_dispand_messages_by_reaction(self.bot, payload)


async def delete_dispand_messages_by_reaction(bot: discord.Client, payload_or_reaction, user=None):
Huyu2239 marked this conversation as resolved.
Show resolved Hide resolved
if isinstance(payload_or_reaction, discord.RawReactionActionEvent):
# when on_raw_reaction_add event
payload = payload_or_reaction
if str(payload.emoji) != DELETE_REACTION_EMOJI:
return
if payload.user_id == bot.user.id:
return

channel = bot.get_channel(payload.channel_id)
message = await channel.fetch_message(payload.message_id)
await delete_dispand_messages(bot, message, payload.user_id)
elif isinstance(payload_or_reaction, discord.Reaction):
# when on_reaction_add event
reaction = payload_or_reaction
if str(reaction.emoji) != DELETE_REACTION_EMOJI:
return
if user.id == bot.user.id:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

user が None だった時の検証は入れないんですか?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

それはエラーになるだけなのでいらないと思います

return
await delete_dispand_messages(bot, reaction.message, user.id)
else:
raise ValueError("payload_or_reaction must be discord.RawReactionActionEvent or discord.Reaction")


async def delete_dispand_messages(bot: discord.Client, message: discord.Message, operator_id: int):
if message.author.id != bot.user.id:
return
elif not message.embeds:
return

embed = message.embeds[0]
if getattr(embed.author, "url", None) is None:
return
data = from_jump_url(embed.author.url)
if not (data["base_author_id"] == operator_id or data["author_id"] == operator_id):
return
await message.delete()
for message_id in data["extra_messages"]:
extra_message = await message.channel.fetch_message(message_id)
if extra_message is not None:
await extra_message.delete()


async def dispand(message):
messages = await extract_message(message)
for m in messages:
sent_messages = []

if m.content or m.attachments:
await message.channel.send(embed=compose_embed(m))
sent_message = await message.channel.send(embed=compose_embed(m))
sent_messages.append(sent_message)
# Send the second and subsequent attachments with embed (named 'embed') respectively:
for attachment in m.attachments[1:]:
embed = Embed()
embed.set_image(
url=attachment.proxy_url
)
await message.channel.send(embed=embed)
sent_attachment_message = await message.channel.send(embed=embed)
sent_messages.append(sent_attachment_message)

for embed in m.embeds:
await message.channel.send(embed=embed)
sent_embed_message = await message.channel.send(embed=embed)
sent_messages.append(sent_embed_message)

# 一番先頭のメッセージにゴミ箱のリアクションをつける
main_message = sent_messages.pop(0)
Huyu2239 marked this conversation as resolved.
Show resolved Hide resolved
await main_message.add_reaction(DELETE_REACTION_EMOJI)
main_embed = main_message.embeds[0]
main_embed.set_author(
name=getattr(main_embed.author, "name", EmptyEmbed),
icon_url=getattr(main_embed.author, "icon_url", EmptyEmbed),
url=make_jump_url(message, m, sent_messages)
)
await main_message.edit(embed=main_embed)


async def extract_message(message):
Expand All @@ -55,6 +127,39 @@ async def fetch_message_from_id(guild, channel_id, message_id):
return message


def make_jump_url(base_message, dispand_message, extra_messages):
"""
make jump url which include more information
:param base_message: メッセージリンクが貼られていたメッセージ
:param dispand_message: 展開中のメッセージ
:param extra_messages: 展開する際にでた二つ目以降のメッセージ(e.g. 画像やembed)
:return: 混入が完了したメッセージリンク
"""
# base_aid: メッセージリンクで飛べる最初のメッセージの送信者のid
# aid: メッセージリンクを送信したユーザーのid
return "{0.jump_url}?base_aid={1.id}&aid={2.id}&extra={3}".format(
chun37 marked this conversation as resolved.
Show resolved Hide resolved
dispand_message,
dispand_message.author,
base_message.author,
",".join([str(i.id) for i in extra_messages])
)


def from_jump_url(url):
"""
メッセージリンクから情報を取得します。
:param url: メッセージリンク
:return: dict
"""
base_url_match = re.match(regex_discord_message_url + regex_extra_url, url)
sizumita marked this conversation as resolved.
Show resolved Hide resolved
data = base_url_match.groupdict()
return {
"base_author_id": int(data["base_author_id"]),
"author_id": int(data["author_id"]),
"extra_messages": [int(_id) for _id in data["extra_messages"].split(",")]
}


def compose_embed(message):
embed = Embed(
description=message.content,
Expand All @@ -63,6 +168,7 @@ def compose_embed(message):
embed.set_author(
name=message.author.display_name,
icon_url=message.author.avatar_url,
url=message.jump_url
chun37 marked this conversation as resolved.
Show resolved Hide resolved
)
embed.set_footer(
text=message.channel.name,
Expand Down