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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@ bot.run(token)

## 関数として使用する場合

on_message内のどこかで実行してください
on_message内のどこかで実行してください。

展開したメッセージを消去する機能を使用するには`on_reaction_add`イベントもしくは`on_raw_reaction_add`イベントのどちらかでdelete_dispand関数を実行してください。
sizumita marked this conversation as resolved.
Show resolved Hide resolved
on_raw_reaction_addの場合はキーワード引数`payload`にRawReactionActionEventを、on_reaction_addの場合はキーワード引数`user`にUser、`reaction`にReactionを指定して下さい。

消去の際のリアクションを変更したい場合は環境変数`DELETE_REACTION_EMOJI`に絵文字を設定してください。

```python
import discord
from dispander import dispand
from dispander import dispand, delete_dispand

client = discord.Client()

Expand All @@ -35,5 +40,11 @@ async def on_message(message):
return
await dispand(message)


@client.event
async def on_raw_reaction_add(payload):
await delete_dispand(client, payload=payload)


client.run(token)
```
117 changes: 114 additions & 3 deletions dispander/module.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
from typing import Optional
import os

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 = os.environ.get("DELETE_REACTION_EMOJI", "\U0001f5d1")


class ExpandDiscordMessageUrl(commands.Cog):
Expand All @@ -18,21 +29,87 @@ 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(self.bot, payload=payload)


async def delete_dispand(bot: discord.Client,
*,
payload: Optional[discord.RawReactionActionEvent] = None,
reaction: Optional[discord.Reaction] = None,
user: Optional[discord.User] = None):
Copy link

Choose a reason for hiding this comment

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

Suggested change
user: Optional[discord.User] = None):
user: Optional[discord.User] = None) -> 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.

わかりにくかったところにつけてあるだけです
ライブラリの方針としてもつけてなさそうなのでいらないかなと

if payload is not None:
# when on_raw_reaction_add event
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(bot, message, payload.user_id)
elif reaction is not None:
# when on_reaction_add event
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(bot, reaction.message, user.id)
else:
raise ValueError("payload or reaction must be setted")


async def _delete_dispand(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 +132,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(",")] if data["extra_messages"] else []
}


def compose_embed(message):
embed = Embed(
description=message.content,
Expand All @@ -63,6 +173,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