feat:删除消息能力

This commit is contained in:
jxxghp
2025-06-22 09:37:01 +08:00
parent 3d92b57f24
commit bd241a5164
7 changed files with 167 additions and 22 deletions

View File

@@ -22,7 +22,7 @@ from app.helper.service import ServiceConfigHelper
from app.log import logger
from app.schemas import TransferInfo, TransferTorrent, ExistMediaInfo, DownloadingTorrent, CommingMessage, Notification, \
WebhookEventInfo, TmdbEpisode, MediaPerson, FileItem, TransferDirectoryConf
from app.schemas.types import TorrentStatus, MediaType, MediaImageType, EventType
from app.schemas.types import TorrentStatus, MediaType, MediaImageType, EventType, MessageChannel
from app.utils.object import ObjectUtils
@@ -641,6 +641,19 @@ class ChainBase(metaclass=ABCMeta):
return self.messagequeue.send_message("post_torrents_message", message=message, torrents=torrents,
immediately=True if message.userid else False)
def delete_message(self, channel: MessageChannel, source: str,
message_id: Union[str, int], chat_id: Optional[Union[str, int]] = None) -> bool:
"""
删除消息
:param channel: 消息渠道
:param source: 消息源(指定特定的消息模块)
:param message_id: 消息ID
:param chat_id: 聊天ID如群组ID
:return: 删除是否成功
"""
return self.run_module("delete_message", channel=channel, source=source,
message_id=message_id, chat_id=chat_id)
def metadata_img(self, mediainfo: MediaInfo,
season: Optional[int] = None, episode: Optional[int] = None) -> Optional[dict]:
"""

View File

@@ -1,4 +1,3 @@
import gc
import re
from typing import Any, Optional, Dict, Union, List
@@ -275,6 +274,14 @@ class MessageChain(ChainBase):
_current_page = 0
# 保存缓存
self.save_cache(user_cache, self._cache_file)
# 删除原消息
if ChannelCapabilityManager.supports_deletion(channel):
self.delete_message(
channel=channel,
source=source,
message_id=original_message_id,
chat_id=original_chat_id
)
# 发送种子数据
logger.info(f"搜索到 {len(contexts)} 条数据,开始发送选择消息 ...")
self.__post_torrents_message(channel=channel,
@@ -505,6 +512,9 @@ class MessageChain(ChainBase):
"""
处理按钮回调
"""
global _current_media
# 提取回调数据
callback_data = text[9:] # 去掉 "CALLBACK:" 前缀
logger.info(f"处理按钮回调:{callback_data}")
@@ -537,7 +547,7 @@ class MessageChain(ChainBase):
text=page_text,
original_message_id=original_message_id, original_chat_id=original_chat_id)
else:
# 发送新消息
# 处理新消息
self.handle_message(channel=channel, source=source, userid=userid, username=username,
text=page_text)
except IndexError:

View File

@@ -222,13 +222,13 @@ class SlackModule(_ModuleBase, _MessageBase[Slack]):
# 使用CALLBACK前缀标识按钮回调
text = f"CALLBACK:{callback_data}"
username = msg_json.get("user", {}).get("name")
# 获取原消息信息用于编辑
message_info = msg_json.get("message", {})
# Slack消息的时间戳作为消息ID
message_ts = message_info.get("ts")
channel_id = msg_json.get("channel", {}).get("id") or msg_json.get("container", {}).get("channel_id")
logger.info(f"收到来自 {client_config.name} 的Slack按钮回调"
f"userid={userid}, username={username}, callback_data={callback_data}")
@@ -320,3 +320,26 @@ class SlackModule(_ModuleBase, _MessageBase[Slack]):
userid=message.userid, buttons=message.buttons,
original_message_id=message.original_message_id,
original_chat_id=message.original_chat_id)
def delete_message(self, channel: MessageChannel, source: str,
message_id: str, chat_id: Optional[str] = None) -> bool:
"""
删除消息
:param channel: 消息渠道
:param source: 指定的消息源
:param message_id: 消息IDSlack中为时间戳
:param chat_id: 聊天ID频道ID
:return: 删除是否成功
"""
success = False
for conf in self.get_configs().values():
if channel != self._channel:
continue
if source != conf.name:
continue
client: Slack = self.get_instance(conf.name)
if client:
result = client.delete_msg(message_id=message_id, chat_id=chat_id)
if result:
success = True
return success

View File

@@ -13,18 +13,16 @@ from app.core.metainfo import MetaInfo
from app.log import logger
from app.utils.string import StringUtils
lock = Lock()
class Slack:
_client: WebClient = None
_service: SocketModeHandler = None
_ds_url = f"http://127.0.0.1:{settings.PORT}/api/v1/message?token={settings.API_TOKEN}"
_channel = ""
def __init__(self, SLACK_OAUTH_TOKEN: Optional[str] = None, SLACK_APP_TOKEN: Optional[str] = None,
def __init__(self, SLACK_OAUTH_TOKEN: Optional[str] = None, SLACK_APP_TOKEN: Optional[str] = None,
SLACK_CHANNEL: Optional[str] = None, **kwargs):
if not SLACK_OAUTH_TOKEN or not SLACK_APP_TOKEN:
@@ -197,7 +195,7 @@ class Slack:
}
]
})
# 判断是编辑消息还是发送新消息
if original_message_id and original_chat_id:
# 编辑消息
@@ -258,7 +256,7 @@ class Slack:
"type": "divider"
})
index = 1
# 如果有自定义按钮,先添加所有媒体项,然后添加统一的按钮
if buttons:
# 添加媒体列表(不带单独的选择按钮)
@@ -288,7 +286,7 @@ class Slack:
}
)
index += 1
# 添加统一的自定义按钮(在所有媒体项之后)
for button_row in buttons:
elements = []
@@ -366,7 +364,7 @@ class Slack:
}
)
index += 1
# 判断是编辑消息还是发送新消息
if original_message_id and original_chat_id:
# 编辑消息
@@ -423,7 +421,7 @@ class Slack:
}]
# 列表
index = 1
# 如果有自定义按钮,先添加种子列表,然后添加统一的按钮
if buttons:
# 添加种子列表(不带单独的选择按钮)
@@ -433,9 +431,9 @@ class Slack:
meta = MetaInfo(torrent.title, torrent.description)
link = torrent.page_url
title_text = f"{meta.season_episode} " \
f"{meta.resource_term} " \
f"{meta.video_term} " \
f"{meta.release_group}"
f"{meta.resource_term} " \
f"{meta.video_term} " \
f"{meta.release_group}"
title_text = re.sub(r"\s+", " ", title_text).strip()
free = torrent.volume_factor
seeder = f"{torrent.seeders}"
@@ -453,7 +451,7 @@ class Slack:
}
)
index += 1
# 添加统一的自定义按钮
for button_row in buttons:
elements = []
@@ -493,9 +491,9 @@ class Slack:
meta = MetaInfo(torrent.title, torrent.description)
link = torrent.page_url
title_text = f"{meta.season_episode} " \
f"{meta.resource_term} " \
f"{meta.video_term} " \
f"{meta.release_group}"
f"{meta.resource_term} " \
f"{meta.video_term} " \
f"{meta.release_group}"
title_text = re.sub(r"\s+", " ", title_text).strip()
free = torrent.volume_factor
seeder = f"{torrent.seeders}"
@@ -530,7 +528,7 @@ class Slack:
}
)
index += 1
# 判断是编辑消息还是发送新消息
if original_message_id and original_chat_id:
# 编辑消息
@@ -552,6 +550,43 @@ class Slack:
logger.error(f"Slack消息发送失败: {msg_e}")
return False
def delete_msg(self, message_id: str, chat_id: Optional[str] = None) -> Optional[bool]:
"""
删除Slack消息
:param message_id: 消息时间戳Slack消息ID
:param chat_id: 频道ID
:return: 删除是否成功
"""
if not self._client:
return None
try:
# 确定要删除消息的频道ID
if chat_id:
target_channel = chat_id
else:
target_channel = self.__find_public_channel()
if not target_channel:
logger.error("无法确定要删除消息的Slack频道")
return False
# 删除消息
result = self._client.chat_delete(
channel=target_channel,
ts=message_id
)
if result.get("ok"):
logger.info(f"成功删除Slack消息: channel={target_channel}, ts={message_id}")
return True
else:
logger.error(f"删除Slack消息失败: {result.get('error', 'unknown error')}")
return False
except Exception as e:
logger.error(f"删除Slack消息异常: {str(e)}")
return False
def __find_public_channel(self):
"""
查找公共频道

View File

@@ -286,6 +286,29 @@ class TelegramModule(_ModuleBase, _MessageBase[Telegram]):
original_message_id=message.original_message_id,
original_chat_id=message.original_chat_id)
def delete_message(self, channel: MessageChannel, source: str,
message_id: int, chat_id: Optional[int] = None) -> bool:
"""
删除消息
:param channel: 消息渠道
:param source: 指定的消息源
:param message_id: 消息ID
:param chat_id: 聊天ID
:return: 删除是否成功
"""
success = False
for conf in self.get_configs().values():
if channel != self._channel:
continue
if source != conf.name:
continue
client: Telegram = self.get_instance(conf.name)
if client:
result = client.delete_msg(message_id=message_id, chat_id=chat_id)
if result:
success = True
return success
def register_commands(self, commands: Dict[str, dict]):
"""
注册命令,实现这个函数接收系统可用的命令菜单

View File

@@ -336,6 +336,35 @@ class Telegram:
logger.error(f"回应回调查询失败:{str(e)}")
return False
def delete_msg(self, message_id: int, chat_id: Optional[int] = None) -> Optional[bool]:
"""
删除Telegram消息
:param message_id: 消息ID
:param chat_id: 聊天ID
:return: 删除是否成功
"""
if not self._telegram_token or not self._telegram_chat_id:
return None
try:
# 确定要删除消息的聊天ID
if chat_id:
target_chat_id = chat_id
else:
target_chat_id = self._telegram_chat_id
# 删除消息
result = self._bot.delete_message(chat_id=target_chat_id, message_id=int(message_id))
if result:
logger.info(f"成功删除Telegram消息: chat_id={target_chat_id}, message_id={message_id}")
return True
else:
logger.error(f"删除Telegram消息失败: chat_id={target_chat_id}, message_id={message_id}")
return False
except Exception as e:
logger.error(f"删除Telegram消息异常: {str(e)}")
return False
def __edit_message(self, chat_id: str, message_id: int, text: str,
buttons: Optional[List[List[dict]]] = None,
image: Optional[str] = None) -> Optional[bool]:
@@ -352,7 +381,7 @@ class Telegram:
return None
try:
# 创建按钮键盘
reply_markup = None
if buttons:

View File

@@ -145,6 +145,8 @@ class ChannelCapability(Enum):
MENU_COMMANDS = "menu_commands"
# 支持消息编辑
MESSAGE_EDITING = "message_editing"
# 支持消息删除
MESSAGE_DELETION = "message_deletion"
# 支持回调查询
CALLBACK_QUERIES = "callback_queries"
# 支持富文本
@@ -182,6 +184,7 @@ class ChannelCapabilityManager:
ChannelCapability.INLINE_BUTTONS,
ChannelCapability.MENU_COMMANDS,
ChannelCapability.MESSAGE_EDITING,
ChannelCapability.MESSAGE_DELETION,
ChannelCapability.CALLBACK_QUERIES,
ChannelCapability.RICH_TEXT,
ChannelCapability.IMAGES,
@@ -205,6 +208,8 @@ class ChannelCapabilityManager:
channel=MessageChannel.Slack,
capabilities={
ChannelCapability.INLINE_BUTTONS,
ChannelCapability.MESSAGE_EDITING,
ChannelCapability.MESSAGE_DELETION,
ChannelCapability.CALLBACK_QUERIES,
ChannelCapability.RICH_TEXT,
ChannelCapability.IMAGES,
@@ -290,6 +295,13 @@ class ChannelCapabilityManager:
"""
return cls.supports_capability(channel, ChannelCapability.MESSAGE_EDITING)
@classmethod
def supports_deletion(cls, channel: MessageChannel) -> bool:
"""
检查渠道是否支持消息删除
"""
return cls.supports_capability(channel, ChannelCapability.MESSAGE_DELETION)
@classmethod
def get_max_buttons_per_row(cls, channel: MessageChannel) -> int:
"""