feat: 添加直接发送视频/图片功能并优化临时目录处理

refactor(WS): 使用TYPE_CHECKING优化导入并延迟导入Bot类
refactor(image_manager): 使用系统临时目录替代自定义临时目录
feat(bili/douyin): 添加直接发送视频/图片功能
chore: 删除forward_test插件并添加furry插件
refactor(main): 移除JIT检查代码并优化插件重载逻辑
This commit is contained in:
2026-01-23 09:32:16 +08:00
parent 36a44f6e96
commit cd7ed30672
8 changed files with 89 additions and 119 deletions

View File

@@ -1,43 +0,0 @@
"""
合并转发消息测试插件
"""
from core.managers.command_manager import matcher
from core.bot import Bot
from models.events.message import MessageEvent
from models.message import MessageSegment
__plugin_meta__ = {
"name": "furry",
"description": "处理 /furry 指令发送furry图片同时也是bot.build_forward_node演示",
"usage": "/furry - 发送一条furry图",
}
@matcher.command("furry")
async def handle_forward_test(bot: Bot, event: MessageEvent, args: list[str]):
"""
处理 /furry 指令发送furry图片同时也是bot.build_forward_node实例
:param bot: Bot 实例
:param event: 消息事件对象
:param args: 指令参数
"""
# 1. 构建消息节点列表
nickname = event.sender.nickname if event.sender else "未知用户"
nodes = [
bot.build_forward_node(user_id=event.self_id, nickname="机器人", message="你要的furry来了"),
bot.build_forward_node(user_id=event.user_id, nickname=nickname, message="让我看看"),
bot.build_forward_node(
user_id=event.self_id,
nickname="机器人",
message=[
MessageSegment.from_text("你要的福瑞图"),
MessageSegment.image("https://api.furry.ist/furry-img/")
]
)
]
try:
# 2. 发送合并转发消息
await bot.send_forwarded_messages(event, nodes)
except Exception as e:
await event.reply(f"发送失败: {e}")

61
plugins/furry.py Normal file
View File

@@ -0,0 +1,61 @@
"""
thpic 插件
提供 /furry 指令用于随机返回一个东方Project的图片。
"""
from core.managers.command_manager import matcher
from core.bot import Bot
from models.events.message import MessageEvent
from models.message import MessageSegment
__plugin_meta__ = {
"name": "furry",
"description": "处理 /furry 指令发送furry出毛图片",
"usage": "/furry - 发送一条furry图",
}
@matcher.command("furry")
async def handle_echo(bot: Bot, event: MessageEvent, args: list[str]):
"""
处理 furry 指令发送一张随机的东方furry图片。
:param bot: Bot 实例(未使用)。
:param event: 消息事件对象。
:param args: 指令参数列表(未使用)。
"""
parts = args
print(parts)
if not parts:
try:
await event.reply(
str(MessageSegment.image("https://api.furry.ist/furry-img/"))
)
except Exception as e:
await event.reply(f"报错了。。。{e}")
else:
if parts[0].isdigit():
nums = int(parts[0])
if nums <= 0:
await event.reply("请输入一个大于0的整数。")
return
elif nums > 10:
await event.reply("请输入一个不大于10的整数。")
return
try:
nodes = []
for _ in range(nums):
nodes.append(
bot.build_forward_node(
user_id=event.self_id,
nickname="机器人",
message=MessageSegment.image(
"https://api.furry.ist/furry-img/"
),
)
)
await bot.send_forwarded_messages(event, nodes)
except Exception as e:
await event.reply(f"报错了。。。{e}")
else:
await event.reply(f"用法不正确。\n\n{__plugin_meta__['usage']}")

View File

@@ -196,33 +196,3 @@ async def handle_github_command(bot, event: MessageEvent):
else:
await event.reply("参数格式错误,请输入:/查仓库 作者/仓库名")
# 注册消息处理器
@matcher.on_message()
async def handle_github_link(event: MessageEvent):
"""
处理消息检测GitHub仓库链接并自动解析
Args:
event (MessageEvent): 消息事件对象
"""
# 忽略机器人自己发送的消息,防止无限循环
if hasattr(event, "user_id") and hasattr(event, "self_id") and event.user_id == event.self_id:
return
# 提取消息文本
message_text = ""
for segment in event.message:
if segment.type == "text":
message_text += segment.data.get("text", "")
# 查找GitHub仓库链接
match = GITHUB_URL_PATTERN.search(message_text)
if match:
owner = match.group(1)
repo = match.group(2)
# 移除可能的.git后缀
repo = repo.replace(".git", "")
logger.info(f"[github_parser] 检测到GitHub仓库链接: {owner}/{repo}")
await process_github_repo(event, owner, repo)

View File

@@ -198,6 +198,7 @@ class BiliParser(BaseParser):
"""
# 检查视频时长
video_message: Union[str, MessageSegment]
direct_url = None
if data['duration'] > 1200: # 20分钟 = 1200秒
video_message = "视频时长超过20分钟不进行解析。"
else:
@@ -244,6 +245,13 @@ class BiliParser(BaseParser):
event.bot.build_forward_node(user_id=event.self_id, nickname=self.nickname, message=video_message)
]
# 同时直接发送视频(如果获取到直链)
if direct_url:
try:
await event.reply(MessageSegment.video(direct_url))
except Exception as e:
logger.error(f"[{self.name}] 直接发送视频失败: {e}")
return nodes
def should_handle_url(self, url: str) -> bool:

View File

@@ -210,15 +210,18 @@ class DouyinParser(BaseParser):
# 尝试添加视频直链(单独节点)
video_success = False
direct_message = None
try:
if data.get('video_url'):
video_url = data.get('video_url', '')
# 检查视频类型
if data.get('type') == 'video':
video_message = MessageSegment.video(video_url)
direct_message = video_message
video_type_text = "视频直链:"
else: # image类型
video_message = MessageSegment.image(video_url) # 单个图片
direct_message = video_message
video_type_text = "图集首图:"
# 构建视频/图片节点
@@ -244,6 +247,13 @@ class DouyinParser(BaseParser):
)
nodes.append(no_video_node)
# 同时直接发送视频/图片(如果获取到直链)
if direct_message:
try:
await event.reply(direct_message)
except Exception as e:
logger.error(f"[{self.name}] 直接发送视频/图片失败: {e}")
return nodes
def should_handle_url(self, url: str) -> bool: