integrations.discord.functions
integrations/discord/functions.py
1""" 2integrations/discord/functions.py 3""" 4 5from typing import TYPE_CHECKING, cast 6 7from discord import Forbidden, NotFound 8from discord.channel import TextChannel 9 10from cls.timekit import ExtendedDatetime as ExtDt 11from integrations.base.interface import FunctionsInterface 12 13if TYPE_CHECKING: 14 from discord import ClientUser, Message 15 16 from integrations.base.interface import MessageParserProtocol 17 from integrations.discord.api import AdapterAPI 18 from integrations.discord.config import SvcConfig 19 from integrations.discord.parser import MessageParser 20 21 22class SvcFunctions(FunctionsInterface): 23 """discord専用関数""" 24 25 def __init__(self, api: "AdapterAPI", conf: "SvcConfig"): 26 super().__init__() 27 28 self.api = api 29 self.conf = conf 30 """個別設定""" 31 32 def post_processing(self, m: "MessageParserProtocol"): 33 """後処理(非同期処理ラッパー) 34 35 Args: 36 m (MessageParserProtocol): メッセージデータ 37 """ 38 39 match m.status.action: 40 case "nothing": 41 return 42 case "change": 43 self.api.bot.loop.create_task(self.update_reaction(m)) 44 case "delete": 45 self.api.bot.loop.create_task(self.delete_reaction(m)) 46 47 async def update_reaction(self, m: "MessageParserProtocol"): 48 """後処理 49 50 Args: 51 m (MessageParserProtocol): メッセージデータ 52 """ 53 54 m = cast("MessageParser", m) 55 self.conf.bot_name = cast("ClientUser", self.conf.bot_name) 56 57 if not hasattr(m, "discord_msg"): 58 return 59 if await self.is_deleted_message(m.discord_msg): 60 return 61 62 EMOJI = { 63 "ok": "\N{WHITE HEAVY CHECK MARK}", 64 "ng": "\N{CROSS MARK}", 65 } 66 67 # 既に付いているリアクションを取得 68 has_ok = False 69 has_ng = False 70 for reaction in m.discord_msg.reactions: 71 if str(reaction.emoji) == EMOJI["ok"]: 72 async for user in reaction.users(): 73 if user == self.conf.bot_name: 74 has_ok = True 75 continue 76 if str(reaction.emoji) == EMOJI["ng"]: 77 async for user in reaction.users(): 78 if user == self.conf.bot_name: 79 has_ng = True 80 continue 81 82 # リアクション処理 83 if m.status.reaction: # NGを外してOKを付ける 84 if has_ng: 85 await m.discord_msg.remove_reaction(EMOJI["ng"], self.conf.bot_name) 86 if not has_ok: 87 await m.discord_msg.add_reaction(EMOJI["ok"]) 88 else: # OKを外してNGを付ける 89 if has_ok: 90 await m.discord_msg.remove_reaction(EMOJI["ok"], self.conf.bot_name) 91 if not has_ng: 92 await m.discord_msg.add_reaction(EMOJI["ng"]) 93 94 async def delete_reaction(self, m: "MessageParserProtocol"): 95 """botが付けたリアクションをすべて削除する 96 97 Args: 98 m (MessageParserProtocol): メッセージデータ 99 """ 100 101 m = cast("MessageParser", m) 102 103 if hasattr(m, "discord_msg"): 104 if await self.is_deleted_message(m.discord_msg): 105 return # 削除済み 106 else: # Messageを持っていない場合はevent_tsとchannel_idを使って検索を試みる 107 if not m.data.channel_id: 108 return # チャンネルIDが空 109 channel = self.api.bot.get_channel(int(m.data.channel_id)) 110 if not isinstance(channel, TextChannel): 111 return # 対象外チャンネル 112 113 async for msg in channel.history( 114 limit=10, 115 oldest_first=True, 116 after=ExtDt(float(m.data.event_ts), seconds=-1).dt, 117 before=ExtDt(float(m.data.event_ts), seconds=1).dt, 118 ): 119 if str(msg.created_at.timestamp()) == m.data.event_ts: 120 m.discord_msg = cast("Message", msg) 121 break 122 return # 該当メッセージなし(削除済み) 123 124 for reaction in m.discord_msg.reactions: 125 async for user in reaction.users(): 126 if user == self.conf.bot_name: 127 await reaction.remove(user) 128 129 async def is_deleted_message(self, message: "Message") -> bool: 130 """メッセージが削除済みか調べる 131 132 Args: 133 message (Message): discordオブジェクト 134 135 Returns: 136 bool: 真偽 137 """ 138 try: 139 await message.channel.fetch_message(message.id) 140 return False 141 except NotFound: 142 return True 143 except Forbidden: 144 return True 145 146 def get_conversations(self, m: "MessageParserProtocol") -> dict: 147 _ = m 148 return {}
23class SvcFunctions(FunctionsInterface): 24 """discord専用関数""" 25 26 def __init__(self, api: "AdapterAPI", conf: "SvcConfig"): 27 super().__init__() 28 29 self.api = api 30 self.conf = conf 31 """個別設定""" 32 33 def post_processing(self, m: "MessageParserProtocol"): 34 """後処理(非同期処理ラッパー) 35 36 Args: 37 m (MessageParserProtocol): メッセージデータ 38 """ 39 40 match m.status.action: 41 case "nothing": 42 return 43 case "change": 44 self.api.bot.loop.create_task(self.update_reaction(m)) 45 case "delete": 46 self.api.bot.loop.create_task(self.delete_reaction(m)) 47 48 async def update_reaction(self, m: "MessageParserProtocol"): 49 """後処理 50 51 Args: 52 m (MessageParserProtocol): メッセージデータ 53 """ 54 55 m = cast("MessageParser", m) 56 self.conf.bot_name = cast("ClientUser", self.conf.bot_name) 57 58 if not hasattr(m, "discord_msg"): 59 return 60 if await self.is_deleted_message(m.discord_msg): 61 return 62 63 EMOJI = { 64 "ok": "\N{WHITE HEAVY CHECK MARK}", 65 "ng": "\N{CROSS MARK}", 66 } 67 68 # 既に付いているリアクションを取得 69 has_ok = False 70 has_ng = False 71 for reaction in m.discord_msg.reactions: 72 if str(reaction.emoji) == EMOJI["ok"]: 73 async for user in reaction.users(): 74 if user == self.conf.bot_name: 75 has_ok = True 76 continue 77 if str(reaction.emoji) == EMOJI["ng"]: 78 async for user in reaction.users(): 79 if user == self.conf.bot_name: 80 has_ng = True 81 continue 82 83 # リアクション処理 84 if m.status.reaction: # NGを外してOKを付ける 85 if has_ng: 86 await m.discord_msg.remove_reaction(EMOJI["ng"], self.conf.bot_name) 87 if not has_ok: 88 await m.discord_msg.add_reaction(EMOJI["ok"]) 89 else: # OKを外してNGを付ける 90 if has_ok: 91 await m.discord_msg.remove_reaction(EMOJI["ok"], self.conf.bot_name) 92 if not has_ng: 93 await m.discord_msg.add_reaction(EMOJI["ng"]) 94 95 async def delete_reaction(self, m: "MessageParserProtocol"): 96 """botが付けたリアクションをすべて削除する 97 98 Args: 99 m (MessageParserProtocol): メッセージデータ 100 """ 101 102 m = cast("MessageParser", m) 103 104 if hasattr(m, "discord_msg"): 105 if await self.is_deleted_message(m.discord_msg): 106 return # 削除済み 107 else: # Messageを持っていない場合はevent_tsとchannel_idを使って検索を試みる 108 if not m.data.channel_id: 109 return # チャンネルIDが空 110 channel = self.api.bot.get_channel(int(m.data.channel_id)) 111 if not isinstance(channel, TextChannel): 112 return # 対象外チャンネル 113 114 async for msg in channel.history( 115 limit=10, 116 oldest_first=True, 117 after=ExtDt(float(m.data.event_ts), seconds=-1).dt, 118 before=ExtDt(float(m.data.event_ts), seconds=1).dt, 119 ): 120 if str(msg.created_at.timestamp()) == m.data.event_ts: 121 m.discord_msg = cast("Message", msg) 122 break 123 return # 該当メッセージなし(削除済み) 124 125 for reaction in m.discord_msg.reactions: 126 async for user in reaction.users(): 127 if user == self.conf.bot_name: 128 await reaction.remove(user) 129 130 async def is_deleted_message(self, message: "Message") -> bool: 131 """メッセージが削除済みか調べる 132 133 Args: 134 message (Message): discordオブジェクト 135 136 Returns: 137 bool: 真偽 138 """ 139 try: 140 await message.channel.fetch_message(message.id) 141 return False 142 except NotFound: 143 return True 144 except Forbidden: 145 return True 146 147 def get_conversations(self, m: "MessageParserProtocol") -> dict: 148 _ = m 149 return {}
discord専用関数
SvcFunctions( api: integrations.discord.api.AdapterAPI, conf: integrations.discord.config.SvcConfig)
33 def post_processing(self, m: "MessageParserProtocol"): 34 """後処理(非同期処理ラッパー) 35 36 Args: 37 m (MessageParserProtocol): メッセージデータ 38 """ 39 40 match m.status.action: 41 case "nothing": 42 return 43 case "change": 44 self.api.bot.loop.create_task(self.update_reaction(m)) 45 case "delete": 46 self.api.bot.loop.create_task(self.delete_reaction(m))
後処理(非同期処理ラッパー)
Arguments:
- m (MessageParserProtocol): メッセージデータ
48 async def update_reaction(self, m: "MessageParserProtocol"): 49 """後処理 50 51 Args: 52 m (MessageParserProtocol): メッセージデータ 53 """ 54 55 m = cast("MessageParser", m) 56 self.conf.bot_name = cast("ClientUser", self.conf.bot_name) 57 58 if not hasattr(m, "discord_msg"): 59 return 60 if await self.is_deleted_message(m.discord_msg): 61 return 62 63 EMOJI = { 64 "ok": "\N{WHITE HEAVY CHECK MARK}", 65 "ng": "\N{CROSS MARK}", 66 } 67 68 # 既に付いているリアクションを取得 69 has_ok = False 70 has_ng = False 71 for reaction in m.discord_msg.reactions: 72 if str(reaction.emoji) == EMOJI["ok"]: 73 async for user in reaction.users(): 74 if user == self.conf.bot_name: 75 has_ok = True 76 continue 77 if str(reaction.emoji) == EMOJI["ng"]: 78 async for user in reaction.users(): 79 if user == self.conf.bot_name: 80 has_ng = True 81 continue 82 83 # リアクション処理 84 if m.status.reaction: # NGを外してOKを付ける 85 if has_ng: 86 await m.discord_msg.remove_reaction(EMOJI["ng"], self.conf.bot_name) 87 if not has_ok: 88 await m.discord_msg.add_reaction(EMOJI["ok"]) 89 else: # OKを外してNGを付ける 90 if has_ok: 91 await m.discord_msg.remove_reaction(EMOJI["ok"], self.conf.bot_name) 92 if not has_ng: 93 await m.discord_msg.add_reaction(EMOJI["ng"])
後処理
Arguments:
- m (MessageParserProtocol): メッセージデータ
95 async def delete_reaction(self, m: "MessageParserProtocol"): 96 """botが付けたリアクションをすべて削除する 97 98 Args: 99 m (MessageParserProtocol): メッセージデータ 100 """ 101 102 m = cast("MessageParser", m) 103 104 if hasattr(m, "discord_msg"): 105 if await self.is_deleted_message(m.discord_msg): 106 return # 削除済み 107 else: # Messageを持っていない場合はevent_tsとchannel_idを使って検索を試みる 108 if not m.data.channel_id: 109 return # チャンネルIDが空 110 channel = self.api.bot.get_channel(int(m.data.channel_id)) 111 if not isinstance(channel, TextChannel): 112 return # 対象外チャンネル 113 114 async for msg in channel.history( 115 limit=10, 116 oldest_first=True, 117 after=ExtDt(float(m.data.event_ts), seconds=-1).dt, 118 before=ExtDt(float(m.data.event_ts), seconds=1).dt, 119 ): 120 if str(msg.created_at.timestamp()) == m.data.event_ts: 121 m.discord_msg = cast("Message", msg) 122 break 123 return # 該当メッセージなし(削除済み) 124 125 for reaction in m.discord_msg.reactions: 126 async for user in reaction.users(): 127 if user == self.conf.bot_name: 128 await reaction.remove(user)
botが付けたリアクションをすべて削除する
Arguments:
- m (MessageParserProtocol): メッセージデータ
async def
is_deleted_message(self, message: discord.message.Message) -> bool:
130 async def is_deleted_message(self, message: "Message") -> bool: 131 """メッセージが削除済みか調べる 132 133 Args: 134 message (Message): discordオブジェクト 135 136 Returns: 137 bool: 真偽 138 """ 139 try: 140 await message.channel.fetch_message(message.id) 141 return False 142 except NotFound: 143 return True 144 except Forbidden: 145 return True
メッセージが削除済みか調べる
Arguments:
- message (Message): discordオブジェクト
Returns:
bool: 真偽