mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-06-08 09:10:32 +08:00
feat(agent): Telegram与Agent相互时支持流式输出
This commit is contained in:
@@ -1,11 +1,16 @@
|
||||
import asyncio
|
||||
import re
|
||||
import threading
|
||||
from typing import Optional, List, Dict, Callable
|
||||
from typing import Optional, List, Dict, Callable, Union
|
||||
from urllib.parse import urljoin, quote
|
||||
|
||||
from telebot import TeleBot, apihelper
|
||||
from telebot.types import BotCommand, InlineKeyboardMarkup, InlineKeyboardButton, InputMediaPhoto
|
||||
from telebot.types import (
|
||||
BotCommand,
|
||||
InlineKeyboardMarkup,
|
||||
InlineKeyboardButton,
|
||||
InputMediaPhoto,
|
||||
)
|
||||
from telegramify_markdown import standardize, telegramify
|
||||
from telegramify_markdown.type import ContentTypes, SentType
|
||||
|
||||
@@ -25,13 +30,22 @@ class RetryException(Exception):
|
||||
|
||||
|
||||
class Telegram:
|
||||
_ds_url = f"http://127.0.0.1:{settings.PORT}/api/v1/message?token={settings.API_TOKEN}"
|
||||
_ds_url = (
|
||||
f"http://127.0.0.1:{settings.PORT}/api/v1/message?token={settings.API_TOKEN}"
|
||||
)
|
||||
_bot: TeleBot = None
|
||||
_callback_handlers: Dict[str, Callable] = {} # 存储回调处理器
|
||||
_user_chat_mapping: Dict[str, str] = {} # userid -> chat_id mapping for reply targeting
|
||||
_user_chat_mapping: Dict[
|
||||
str, str
|
||||
] = {} # userid -> chat_id mapping for reply targeting
|
||||
_bot_username: Optional[str] = None # Bot username for mention detection
|
||||
|
||||
def __init__(self, TELEGRAM_TOKEN: Optional[str] = None, TELEGRAM_CHAT_ID: Optional[str] = None, **kwargs):
|
||||
def __init__(
|
||||
self,
|
||||
TELEGRAM_TOKEN: Optional[str] = None,
|
||||
TELEGRAM_CHAT_ID: Optional[str] = None,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
初始化参数
|
||||
"""
|
||||
@@ -46,8 +60,8 @@ class Telegram:
|
||||
if self._telegram_token and self._telegram_chat_id:
|
||||
# telegram bot api 地址,格式:https://api.telegram.org
|
||||
if kwargs.get("API_URL"):
|
||||
apihelper.API_URL = urljoin(kwargs["API_URL"], '/bot{0}/{1}')
|
||||
apihelper.FILE_URL = urljoin(kwargs["API_URL"], '/file/bot{0}/{1}')
|
||||
apihelper.API_URL = urljoin(kwargs["API_URL"], "/bot{0}/{1}")
|
||||
apihelper.FILE_URL = urljoin(kwargs["API_URL"], "/file/bot{0}/{1}")
|
||||
else:
|
||||
apihelper.proxy = settings.PROXY
|
||||
# bot
|
||||
@@ -66,12 +80,15 @@ class Telegram:
|
||||
# 标记渠道来源
|
||||
if kwargs.get("name"):
|
||||
# URL encode the source name to handle special characters
|
||||
encoded_name = quote(kwargs.get('name'), safe='')
|
||||
encoded_name = quote(kwargs.get("name"), safe="")
|
||||
self._ds_url = f"{self._ds_url}&source={encoded_name}"
|
||||
|
||||
@_bot.message_handler(commands=['start', 'help'])
|
||||
@_bot.message_handler(commands=["start", "help"])
|
||||
def send_welcome(message):
|
||||
_bot.reply_to(message, "温馨提示:直接发送名称或`订阅`+名称,搜索或订阅电影、电视剧")
|
||||
_bot.reply_to(
|
||||
message,
|
||||
"温馨提示:直接发送名称或`订阅`+名称,搜索或订阅电影、电视剧",
|
||||
)
|
||||
|
||||
@_bot.message_handler(func=lambda message: True)
|
||||
def echo_all(message):
|
||||
@@ -82,7 +99,7 @@ class Telegram:
|
||||
if self._should_process_message(message):
|
||||
# 发送正在输入状态
|
||||
try:
|
||||
_bot.send_chat_action(message.chat.id, 'typing')
|
||||
_bot.send_chat_action(message.chat.id, "typing")
|
||||
except Exception as err:
|
||||
logger.error(f"发送Telegram正在输入状态失败:{err}")
|
||||
RequestUtils(timeout=15).post_res(self._ds_url, json=message.json)
|
||||
@@ -94,7 +111,9 @@ class Telegram:
|
||||
"""
|
||||
try:
|
||||
# Update user-chat mapping for callbacks too
|
||||
self._update_user_chat_mapping(call.from_user.id, call.message.chat.id)
|
||||
self._update_user_chat_mapping(
|
||||
call.from_user.id, call.message.chat.id
|
||||
)
|
||||
|
||||
# 解析回调数据
|
||||
callback_data = call.data
|
||||
@@ -111,9 +130,9 @@ class Telegram:
|
||||
"message_id": call.message.message_id,
|
||||
"chat": {
|
||||
"id": call.message.chat.id,
|
||||
}
|
||||
},
|
||||
},
|
||||
"data": callback_data
|
||||
"data": callback_data,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +141,7 @@ class Telegram:
|
||||
|
||||
# 发送正在输入状态
|
||||
try:
|
||||
_bot.send_chat_action(call.message.chat.id, 'typing')
|
||||
_bot.send_chat_action(call.message.chat.id, "typing")
|
||||
except Exception as e:
|
||||
logger.error(f"发送Telegram正在输入状态失败:{e}")
|
||||
|
||||
@@ -179,17 +198,17 @@ class Telegram:
|
||||
:return: 是否处理
|
||||
"""
|
||||
# 私聊消息总是处理
|
||||
if message.chat.type == 'private':
|
||||
if message.chat.type == "private":
|
||||
logger.debug(f"处理私聊消息:用户 {message.from_user.id}")
|
||||
return True
|
||||
|
||||
# 群聊中的命令消息总是处理(以/开头)
|
||||
if message.text and message.text.startswith('/'):
|
||||
if message.text and message.text.startswith("/"):
|
||||
logger.debug(f"处理群聊命令消息:{message.text[:20]}...")
|
||||
return True
|
||||
|
||||
# 群聊中检查是否@了机器人
|
||||
if message.chat.type in ['group', 'supergroup']:
|
||||
if message.chat.type in ["group", "supergroup"]:
|
||||
if not self._bot_username:
|
||||
# 如果没有获取到bot用户名,为了安全起见处理所有消息
|
||||
logger.debug("未获取到bot用户名,处理所有群聊消息")
|
||||
@@ -203,14 +222,20 @@ class Telegram:
|
||||
# 检查消息实体中是否有提及bot
|
||||
if message.entities:
|
||||
for entity in message.entities:
|
||||
if entity.type == 'mention':
|
||||
mention_text = message.text[entity.offset:entity.offset + entity.length]
|
||||
if entity.type == "mention":
|
||||
mention_text = message.text[
|
||||
entity.offset : entity.offset + entity.length
|
||||
]
|
||||
if mention_text == f"@{self._bot_username}":
|
||||
logger.debug(f"通过实体检测到@{self._bot_username},处理群聊消息")
|
||||
logger.debug(
|
||||
f"通过实体检测到@{self._bot_username},处理群聊消息"
|
||||
)
|
||||
return True
|
||||
|
||||
# 群聊中没有@机器人,不处理
|
||||
logger.debug(f"群聊消息未@机器人,跳过处理:{message.text[:30] if message.text else 'No text'}...")
|
||||
logger.debug(
|
||||
f"群聊消息未@机器人,跳过处理:{message.text[:30] if message.text else 'No text'}..."
|
||||
)
|
||||
return False
|
||||
|
||||
# 其他类型的聊天默认处理
|
||||
@@ -223,11 +248,17 @@ class Telegram:
|
||||
"""
|
||||
return self._bot is not None
|
||||
|
||||
def send_msg(self, title: str, text: Optional[str] = None, image: Optional[str] = None,
|
||||
userid: Optional[str] = None, link: Optional[str] = None,
|
||||
buttons: Optional[List[List[dict]]] = None,
|
||||
original_message_id: Optional[int] = None,
|
||||
original_chat_id: Optional[str] = None) -> Optional[bool]:
|
||||
def send_msg(
|
||||
self,
|
||||
title: str,
|
||||
text: Optional[str] = None,
|
||||
image: Optional[str] = None,
|
||||
userid: Optional[str] = None,
|
||||
link: Optional[str] = None,
|
||||
buttons: Optional[List[List[dict]]] = None,
|
||||
original_message_id: Optional[int] = None,
|
||||
original_chat_id: Optional[str] = None,
|
||||
) -> Optional[dict]:
|
||||
"""
|
||||
发送Telegram消息
|
||||
:param title: 消息标题
|
||||
@@ -238,14 +269,14 @@ class Telegram:
|
||||
:param buttons: 按钮列表,格式:[[{"text": "按钮文本", "callback_data": "回调数据"}]]
|
||||
:param original_message_id: 原消息ID,如果提供则编辑原消息
|
||||
:param original_chat_id: 原消息的聊天ID,编辑消息时需要
|
||||
|
||||
:return: 包含 message_id, chat_id, success 的字典
|
||||
"""
|
||||
if not self._telegram_token or not self._telegram_chat_id:
|
||||
return None
|
||||
|
||||
if not title and not text:
|
||||
logger.warn("标题和内容不能同时为空")
|
||||
return False
|
||||
return {"success": False}
|
||||
|
||||
try:
|
||||
# 标准化标题后再加粗,避免**符号被显示为文本
|
||||
@@ -275,17 +306,39 @@ class Telegram:
|
||||
# 判断是编辑消息还是发送新消息
|
||||
if original_message_id and original_chat_id:
|
||||
# 编辑消息
|
||||
return self.__edit_message(original_chat_id, original_message_id, caption, buttons, image)
|
||||
result = self.__edit_message(
|
||||
original_chat_id, original_message_id, caption, buttons, image
|
||||
)
|
||||
return {
|
||||
"success": bool(result),
|
||||
"message_id": original_message_id,
|
||||
"chat_id": original_chat_id,
|
||||
}
|
||||
else:
|
||||
# 发送新消息
|
||||
return self.__send_request(userid=chat_id, image=image, caption=caption, reply_markup=reply_markup)
|
||||
sent = self.__send_request(
|
||||
userid=chat_id,
|
||||
image=image,
|
||||
caption=caption,
|
||||
reply_markup=reply_markup,
|
||||
)
|
||||
if sent and hasattr(sent, "message_id"):
|
||||
return {
|
||||
"success": True,
|
||||
"message_id": sent.message_id,
|
||||
"chat_id": sent.chat.id if hasattr(sent, "chat") else chat_id,
|
||||
}
|
||||
elif sent:
|
||||
return {"success": True}
|
||||
return {"success": False}
|
||||
|
||||
except Exception as msg_e:
|
||||
logger.error(f"发送消息失败:{msg_e}")
|
||||
return False
|
||||
return {"success": False}
|
||||
|
||||
def _determine_target_chat_id(self, userid: Optional[str] = None,
|
||||
original_chat_id: Optional[str] = None) -> str:
|
||||
def _determine_target_chat_id(
|
||||
self, userid: Optional[str] = None, original_chat_id: Optional[str] = None
|
||||
) -> str:
|
||||
"""
|
||||
确定目标聊天ID,使用用户映射确保回复到正确的聊天
|
||||
:param userid: 用户ID
|
||||
@@ -307,11 +360,16 @@ class Telegram:
|
||||
# 3. 最后使用默认聊天ID
|
||||
return self._telegram_chat_id
|
||||
|
||||
def send_medias_msg(self, medias: List[MediaInfo], userid: Optional[str] = None,
|
||||
title: Optional[str] = None, link: Optional[str] = None,
|
||||
buttons: Optional[List[List[Dict]]] = None,
|
||||
original_message_id: Optional[int] = None,
|
||||
original_chat_id: Optional[str] = None) -> Optional[bool]:
|
||||
def send_medias_msg(
|
||||
self,
|
||||
medias: List[MediaInfo],
|
||||
userid: Optional[str] = None,
|
||||
title: Optional[str] = None,
|
||||
link: Optional[str] = None,
|
||||
buttons: Optional[List[List[Dict]]] = None,
|
||||
original_message_id: Optional[int] = None,
|
||||
original_chat_id: Optional[str] = None,
|
||||
) -> Optional[bool]:
|
||||
"""
|
||||
发送媒体列表消息
|
||||
:param medias: 媒体信息列表
|
||||
@@ -331,18 +389,22 @@ class Telegram:
|
||||
if not image:
|
||||
image = media.get_message_image()
|
||||
if media.vote_average:
|
||||
caption = "%s\n%s. [%s](%s)\n_%s,%s_" % (caption,
|
||||
index,
|
||||
media.title_year,
|
||||
media.detail_link,
|
||||
f"类型:{media.type.value}",
|
||||
f"评分:{media.vote_average}")
|
||||
caption = "%s\n%s. [%s](%s)\n_%s,%s_" % (
|
||||
caption,
|
||||
index,
|
||||
media.title_year,
|
||||
media.detail_link,
|
||||
f"类型:{media.type.value}",
|
||||
f"评分:{media.vote_average}",
|
||||
)
|
||||
else:
|
||||
caption = "%s\n%s. [%s](%s)\n_%s_" % (caption,
|
||||
index,
|
||||
media.title_year,
|
||||
media.detail_link,
|
||||
f"类型:{media.type.value}")
|
||||
caption = "%s\n%s. [%s](%s)\n_%s_" % (
|
||||
caption,
|
||||
index,
|
||||
media.title_year,
|
||||
media.detail_link,
|
||||
f"类型:{media.type.value}",
|
||||
)
|
||||
index += 1
|
||||
|
||||
if link:
|
||||
@@ -359,20 +421,32 @@ class Telegram:
|
||||
# 判断是编辑消息还是发送新消息
|
||||
if original_message_id and original_chat_id:
|
||||
# 编辑消息
|
||||
return self.__edit_message(original_chat_id, original_message_id, caption, buttons, image)
|
||||
return self.__edit_message(
|
||||
original_chat_id, original_message_id, caption, buttons, image
|
||||
)
|
||||
else:
|
||||
# 发送新消息
|
||||
return self.__send_request(userid=chat_id, image=image, caption=caption, reply_markup=reply_markup)
|
||||
return self.__send_request(
|
||||
userid=chat_id,
|
||||
image=image,
|
||||
caption=caption,
|
||||
reply_markup=reply_markup,
|
||||
)
|
||||
|
||||
except Exception as msg_e:
|
||||
logger.error(f"发送消息失败:{msg_e}")
|
||||
return False
|
||||
|
||||
def send_torrents_msg(self, torrents: List[Context],
|
||||
userid: Optional[str] = None, title: Optional[str] = None,
|
||||
link: Optional[str] = None, buttons: Optional[List[List[Dict]]] = None,
|
||||
original_message_id: Optional[int] = None,
|
||||
original_chat_id: Optional[str] = None) -> Optional[bool]:
|
||||
def send_torrents_msg(
|
||||
self,
|
||||
torrents: List[Context],
|
||||
userid: Optional[str] = None,
|
||||
title: Optional[str] = None,
|
||||
link: Optional[str] = None,
|
||||
buttons: Optional[List[List[Dict]]] = None,
|
||||
original_message_id: Optional[int] = None,
|
||||
original_chat_id: Optional[str] = None,
|
||||
) -> Optional[bool]:
|
||||
"""
|
||||
发送种子列表消息
|
||||
:param torrents: 种子信息列表
|
||||
@@ -394,15 +468,19 @@ class Telegram:
|
||||
site_name = torrent.site_name
|
||||
meta = MetaInfo(torrent.title, torrent.description)
|
||||
link = torrent.page_url
|
||||
title = f"{meta.season_episode} " \
|
||||
f"{meta.resource_term} " \
|
||||
f"{meta.video_term} " \
|
||||
f"{meta.release_group}"
|
||||
title = (
|
||||
f"{meta.season_episode} "
|
||||
f"{meta.resource_term} "
|
||||
f"{meta.video_term} "
|
||||
f"{meta.release_group}"
|
||||
)
|
||||
title = re.sub(r"\s+", " ", title).strip()
|
||||
free = torrent.volume_factor
|
||||
seeder = f"{torrent.seeders}↑"
|
||||
caption = f"{caption}\n{index}.【{site_name}】[{title}]({link}) " \
|
||||
f"{StringUtils.str_filesize(torrent.size)} {free} {seeder}"
|
||||
caption = (
|
||||
f"{caption}\n{index}.【{site_name}】[{title}]({link}) "
|
||||
f"{StringUtils.str_filesize(torrent.size)} {free} {seeder}"
|
||||
)
|
||||
index += 1
|
||||
|
||||
if link:
|
||||
@@ -419,10 +497,17 @@ class Telegram:
|
||||
# 判断是编辑消息还是发送新消息
|
||||
if original_message_id and original_chat_id:
|
||||
# 编辑消息(种子消息通常没有图片)
|
||||
return self.__edit_message(original_chat_id, original_message_id, caption, buttons, image)
|
||||
return self.__edit_message(
|
||||
original_chat_id, original_message_id, caption, buttons, image
|
||||
)
|
||||
else:
|
||||
# 发送新消息
|
||||
return self.__send_request(userid=chat_id, image=image, caption=caption, reply_markup=reply_markup)
|
||||
return self.__send_request(
|
||||
userid=chat_id,
|
||||
image=image,
|
||||
caption=caption,
|
||||
reply_markup=reply_markup,
|
||||
)
|
||||
|
||||
except Exception as msg_e:
|
||||
logger.error(f"发送消息失败:{msg_e}")
|
||||
@@ -444,13 +529,19 @@ class Telegram:
|
||||
btn = InlineKeyboardButton(text=button["text"], url=button["url"])
|
||||
else:
|
||||
# 回调按钮
|
||||
btn = InlineKeyboardButton(text=button["text"], callback_data=button["callback_data"])
|
||||
btn = InlineKeyboardButton(
|
||||
text=button["text"], callback_data=button["callback_data"]
|
||||
)
|
||||
button_row.append(btn)
|
||||
keyboard.append(button_row)
|
||||
return InlineKeyboardMarkup(keyboard)
|
||||
|
||||
def answer_callback_query(self, callback_query_id: int, text: Optional[str] = None,
|
||||
show_alert: bool = False) -> Optional[bool]:
|
||||
def answer_callback_query(
|
||||
self,
|
||||
callback_query_id: int,
|
||||
text: Optional[str] = None,
|
||||
show_alert: bool = False,
|
||||
) -> Optional[bool]:
|
||||
"""
|
||||
回应回调查询
|
||||
"""
|
||||
@@ -458,13 +549,17 @@ class Telegram:
|
||||
return None
|
||||
|
||||
try:
|
||||
self._bot.answer_callback_query(callback_query_id, text=text, show_alert=show_alert)
|
||||
self._bot.answer_callback_query(
|
||||
callback_query_id, text=text, show_alert=show_alert
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"回应回调查询失败:{str(e)}")
|
||||
return False
|
||||
|
||||
def delete_msg(self, message_id: int, chat_id: Optional[int] = None) -> Optional[bool]:
|
||||
def delete_msg(
|
||||
self, message_id: int, chat_id: Optional[int] = None
|
||||
) -> Optional[bool]:
|
||||
"""
|
||||
删除Telegram消息
|
||||
:param message_id: 消息ID
|
||||
@@ -482,20 +577,68 @@ class Telegram:
|
||||
target_chat_id = self._telegram_chat_id
|
||||
|
||||
# 删除消息
|
||||
result = self._bot.delete_message(chat_id=target_chat_id, message_id=int(message_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}")
|
||||
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}")
|
||||
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]:
|
||||
def edit_msg(
|
||||
self,
|
||||
chat_id: Union[str, int],
|
||||
message_id: Union[str, int],
|
||||
text: str,
|
||||
title: Optional[str] = None,
|
||||
) -> Optional[bool]:
|
||||
"""
|
||||
编辑Telegram消息(公开方法)
|
||||
:param chat_id: 聊天ID
|
||||
:param message_id: 消息ID
|
||||
:param text: 新的消息内容
|
||||
:param title: 消息标题
|
||||
:return: 编辑是否成功
|
||||
"""
|
||||
if not self._bot:
|
||||
return None
|
||||
|
||||
try:
|
||||
# 组合标题和文本
|
||||
if title:
|
||||
bold_title = f"**{standardize(title).removesuffix(chr(10))}**"
|
||||
caption = f"{bold_title}\n{text}" if text else bold_title
|
||||
elif text:
|
||||
caption = text
|
||||
else:
|
||||
return False
|
||||
|
||||
return self.__edit_message(
|
||||
chat_id=str(chat_id),
|
||||
message_id=int(message_id),
|
||||
text=caption,
|
||||
)
|
||||
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]:
|
||||
"""
|
||||
编辑已发送的消息
|
||||
:param chat_id: 聊天ID
|
||||
@@ -509,7 +652,6 @@ class Telegram:
|
||||
return None
|
||||
|
||||
try:
|
||||
|
||||
# 创建按钮键盘
|
||||
reply_markup = None
|
||||
if buttons:
|
||||
@@ -517,12 +659,14 @@ class Telegram:
|
||||
|
||||
if image:
|
||||
# 如果有图片,使用edit_message_media
|
||||
media = InputMediaPhoto(media=image, caption=standardize(text), parse_mode="MarkdownV2")
|
||||
media = InputMediaPhoto(
|
||||
media=image, caption=standardize(text), parse_mode="MarkdownV2"
|
||||
)
|
||||
self._bot.edit_message_media(
|
||||
chat_id=chat_id,
|
||||
message_id=message_id,
|
||||
media=media,
|
||||
reply_markup=reply_markup
|
||||
reply_markup=reply_markup,
|
||||
)
|
||||
else:
|
||||
# 如果没有图片,使用edit_message_text
|
||||
@@ -531,23 +675,29 @@ class Telegram:
|
||||
message_id=message_id,
|
||||
text=standardize(text),
|
||||
parse_mode="MarkdownV2",
|
||||
reply_markup=reply_markup
|
||||
reply_markup=reply_markup,
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"编辑消息失败:{str(e)}")
|
||||
return False
|
||||
|
||||
def __send_request(self, userid: Optional[str] = None, image="", caption="",
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None) -> bool:
|
||||
def __send_request(
|
||||
self,
|
||||
userid: Optional[str] = None,
|
||||
image="",
|
||||
caption="",
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
):
|
||||
"""
|
||||
向Telegram发送报文
|
||||
向Telegram发送报文,返回发送的消息对象
|
||||
:param reply_markup: 内联键盘
|
||||
:return: 发送成功返回消息对象,失败返回None
|
||||
"""
|
||||
kwargs = {
|
||||
'chat_id': userid or self._telegram_chat_id,
|
||||
'parse_mode': "MarkdownV2",
|
||||
'reply_markup': reply_markup
|
||||
"chat_id": userid or self._telegram_chat_id,
|
||||
"parse_mode": "MarkdownV2",
|
||||
"reply_markup": reply_markup,
|
||||
}
|
||||
|
||||
# 处理图片
|
||||
@@ -562,10 +712,10 @@ class Telegram:
|
||||
sent_idx = set()
|
||||
ret = self.__send_long_message(image, caption, sent_idx, **kwargs)
|
||||
|
||||
return ret is not None
|
||||
return ret
|
||||
except Exception as e:
|
||||
logger.error(f"发送Telegram消息失败: {e}")
|
||||
return False
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def __process_image(image_url: Optional[str]) -> Optional[bytes]:
|
||||
@@ -587,27 +737,28 @@ class Telegram:
|
||||
try:
|
||||
if image:
|
||||
return self._bot.send_photo(
|
||||
photo=image,
|
||||
caption=standardize(caption),
|
||||
**kwargs
|
||||
photo=image, caption=standardize(caption), **kwargs
|
||||
)
|
||||
else:
|
||||
return self._bot.send_message(
|
||||
text=standardize(caption),
|
||||
**kwargs
|
||||
)
|
||||
return self._bot.send_message(text=standardize(caption), **kwargs)
|
||||
except Exception:
|
||||
raise RetryException(f"发送{'图片' if image else '文本'}消息失败")
|
||||
|
||||
@retry(RetryException, logger=logger)
|
||||
def __send_long_message(self, image: Optional[bytes], caption: str, sent_idx: set, **kwargs):
|
||||
def __send_long_message(
|
||||
self, image: Optional[bytes], caption: str, sent_idx: set, **kwargs
|
||||
):
|
||||
"""
|
||||
发送长消息
|
||||
"""
|
||||
try:
|
||||
reply_markup = kwargs.pop("reply_markup", None)
|
||||
|
||||
boxs: SentType = ThreadHelper().submit(lambda x: asyncio.run(telegramify(x)), caption).result()
|
||||
boxs: SentType = (
|
||||
ThreadHelper()
|
||||
.submit(lambda x: asyncio.run(telegramify(x)), caption)
|
||||
.result()
|
||||
)
|
||||
|
||||
ret = None
|
||||
for i, item in enumerate(boxs):
|
||||
@@ -618,24 +769,27 @@ class Telegram:
|
||||
current_reply_markup = reply_markup if i == 0 else None
|
||||
|
||||
if item.content_type == ContentTypes.TEXT and (i != 0 or not image):
|
||||
ret = self._bot.send_message(**kwargs,
|
||||
text=item.content,
|
||||
reply_markup=current_reply_markup
|
||||
ret = self._bot.send_message(
|
||||
**kwargs, text=item.content, reply_markup=current_reply_markup
|
||||
)
|
||||
|
||||
elif item.content_type == ContentTypes.PHOTO or (image and i == 0):
|
||||
ret = self._bot.send_photo(**kwargs,
|
||||
photo=(getattr(item, "file_name", ""),
|
||||
getattr(item, "file_data", image)),
|
||||
ret = self._bot.send_photo(
|
||||
**kwargs,
|
||||
photo=(
|
||||
getattr(item, "file_name", ""),
|
||||
getattr(item, "file_data", image),
|
||||
),
|
||||
caption=getattr(item, "caption", item.content),
|
||||
reply_markup=current_reply_markup
|
||||
reply_markup=current_reply_markup,
|
||||
)
|
||||
|
||||
elif item.content_type == ContentTypes.FILE:
|
||||
ret = self._bot.send_document(**kwargs,
|
||||
ret = self._bot.send_document(
|
||||
**kwargs,
|
||||
document=(item.file_name, item.file_data),
|
||||
caption=item.caption,
|
||||
reply_markup=current_reply_markup
|
||||
reply_markup=current_reply_markup,
|
||||
)
|
||||
|
||||
sent_idx.add(i)
|
||||
@@ -658,8 +812,8 @@ class Telegram:
|
||||
self._bot.delete_my_commands()
|
||||
self._bot.set_my_commands(
|
||||
commands=[
|
||||
BotCommand(cmd[1:], str(desc.get("description"))) for cmd, desc in
|
||||
commands.items()
|
||||
BotCommand(cmd[1:], str(desc.get("description")))
|
||||
for cmd, desc in commands.items()
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user