feat:初版
This commit is contained in:
3
plugins/RandomVideo/__init__.py
Normal file
3
plugins/RandomVideo/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .main import RandomVideo
|
||||
|
||||
__all__ = ["RandomVideo"]
|
||||
226
plugins/RandomVideo/main.py
Normal file
226
plugins/RandomVideo/main.py
Normal file
@@ -0,0 +1,226 @@
|
||||
"""
|
||||
随机视频插件
|
||||
|
||||
用户发送关键词获取随机小姐姐视频
|
||||
"""
|
||||
|
||||
import tomllib
|
||||
import httpx
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from loguru import logger
|
||||
from typing import List
|
||||
from utils.plugin_base import PluginBase
|
||||
from utils.decorators import on_text_message
|
||||
|
||||
|
||||
class RandomVideo(PluginBase):
|
||||
"""随机视频插件"""
|
||||
|
||||
description = "随机小姐姐视频"
|
||||
author = "ShiHao"
|
||||
version = "1.0.0"
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.config = None
|
||||
|
||||
async def async_init(self):
|
||||
"""异步初始化"""
|
||||
config_path = Path(__file__).parent / "config.toml"
|
||||
with open(config_path, "rb") as f:
|
||||
self.config = tomllib.load(f)
|
||||
logger.success("随机视频插件已加载")
|
||||
|
||||
@on_text_message(priority=65)
|
||||
async def handle_message(self, bot, message: dict):
|
||||
"""处理文本消息"""
|
||||
content = message.get("Content", "").strip()
|
||||
from_wxid = message.get("FromWxid", "")
|
||||
is_group = message.get("IsGroup", False)
|
||||
|
||||
# 精确匹配关键词
|
||||
if content not in self.config["behavior"]["keywords"]:
|
||||
return True
|
||||
|
||||
if not self.config["behavior"]["enabled"]:
|
||||
return True
|
||||
|
||||
# 检查群聊过滤
|
||||
if is_group:
|
||||
enabled_groups = self.config["behavior"]["enabled_groups"]
|
||||
disabled_groups = self.config["behavior"]["disabled_groups"]
|
||||
|
||||
if from_wxid in disabled_groups:
|
||||
return True
|
||||
if enabled_groups and from_wxid not in enabled_groups:
|
||||
return True
|
||||
|
||||
logger.info(f"收到随机视频请求: {from_wxid}")
|
||||
|
||||
try:
|
||||
# 获取视频URL
|
||||
video_url = await self._fetch_video_url()
|
||||
if not video_url:
|
||||
await bot.send_text(from_wxid, self.config["messages"]["api_error"])
|
||||
return False
|
||||
|
||||
# 下载视频
|
||||
video_path = await self._download_video(video_url)
|
||||
if not video_path:
|
||||
await bot.send_text(from_wxid, self.config["messages"]["download_error"])
|
||||
return False
|
||||
|
||||
# 发送视频
|
||||
success = await bot.send_file(from_wxid, video_path)
|
||||
if success:
|
||||
logger.success(f"随机视频发送成功: {from_wxid}")
|
||||
# 延迟删除,等待微信上传完成
|
||||
import asyncio
|
||||
asyncio.create_task(self._delayed_cleanup(video_path, 120))
|
||||
else:
|
||||
await bot.send_text(from_wxid, self.config["messages"]["send_error"])
|
||||
logger.error(f"随机视频发送失败: {from_wxid}")
|
||||
# 立即删除失败的文件
|
||||
try:
|
||||
Path(video_path).unlink()
|
||||
except:
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"随机视频处理失败: {e}")
|
||||
await bot.send_text(from_wxid, self.config["messages"]["api_error"])
|
||||
|
||||
return False
|
||||
|
||||
async def _delayed_cleanup(self, file_path: str, delay: int):
|
||||
"""延迟删除文件"""
|
||||
import asyncio
|
||||
await asyncio.sleep(delay)
|
||||
try:
|
||||
Path(file_path).unlink()
|
||||
logger.info(f"已清理临时文件: {file_path}")
|
||||
except Exception as e:
|
||||
logger.warning(f"清理临时文件失败: {e}")
|
||||
|
||||
async def _fetch_video_url(self) -> str:
|
||||
"""获取视频URL"""
|
||||
try:
|
||||
timeout = httpx.Timeout(self.config["api"]["timeout"])
|
||||
async with httpx.AsyncClient(timeout=timeout) as client:
|
||||
response = await client.get(self.config["api"]["url"])
|
||||
|
||||
if response.status_code != 200:
|
||||
logger.error(f"API返回错误: {response.status_code}")
|
||||
return ""
|
||||
|
||||
result = response.json()
|
||||
|
||||
if result.get("code") != 200:
|
||||
logger.error(f"API错误: {result.get('msg')}")
|
||||
return ""
|
||||
|
||||
video_url = result.get("data", "")
|
||||
logger.info(f"获取到视频URL: {video_url}")
|
||||
return video_url
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取视频URL失败: {e}")
|
||||
return ""
|
||||
|
||||
async def _download_video(self, video_url: str) -> str:
|
||||
"""下载视频到本地"""
|
||||
try:
|
||||
videos_dir = Path(__file__).parent / "videos"
|
||||
videos_dir.mkdir(exist_ok=True)
|
||||
|
||||
filename = f"random_{uuid.uuid4().hex[:8]}.mp4"
|
||||
file_path = videos_dir / filename
|
||||
|
||||
timeout = httpx.Timeout(connect=10.0, read=60.0, write=10.0, pool=10.0)
|
||||
async with httpx.AsyncClient(timeout=timeout) as client:
|
||||
response = await client.get(video_url)
|
||||
response.raise_for_status()
|
||||
|
||||
with open(file_path, "wb") as f:
|
||||
f.write(response.content)
|
||||
|
||||
logger.info(f"视频下载成功: {file_path}")
|
||||
return str(file_path.resolve())
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"下载视频失败: {e}")
|
||||
return ""
|
||||
|
||||
def get_llm_tools(self) -> List[dict]:
|
||||
"""返回LLM工具定义"""
|
||||
return [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_random_video",
|
||||
"description": "获取随机小姐姐视频。当用户想看随机视频、小姐姐视频、擦边视频时调用",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
"required": []
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
async def execute_llm_tool(self, tool_name: str, arguments: dict, bot, from_wxid: str) -> dict:
|
||||
"""执行LLM工具调用"""
|
||||
try:
|
||||
if not self.config["behavior"]["enabled"]:
|
||||
return {"success": False, "message": "随机视频插件未启用"}
|
||||
|
||||
# 检查群聊过滤
|
||||
is_group = from_wxid.endswith("@chatroom")
|
||||
if is_group:
|
||||
enabled_groups = self.config["behavior"]["enabled_groups"]
|
||||
disabled_groups = self.config["behavior"]["disabled_groups"]
|
||||
|
||||
if from_wxid in disabled_groups:
|
||||
return {"success": False, "message": "此群聊未启用随机视频功能"}
|
||||
if enabled_groups and from_wxid not in enabled_groups:
|
||||
return {"success": False, "message": "此群聊未启用随机视频功能"}
|
||||
|
||||
if tool_name == "get_random_video":
|
||||
logger.info(f"LLM工具调用获取随机视频: {from_wxid}")
|
||||
|
||||
# 获取视频URL
|
||||
video_url = await self._fetch_video_url()
|
||||
if not video_url:
|
||||
await bot.send_text(from_wxid, self.config["messages"]["api_error"])
|
||||
return {"success": False, "message": "获取视频URL失败"}
|
||||
|
||||
# 下载视频
|
||||
video_path = await self._download_video(video_url)
|
||||
if not video_path:
|
||||
await bot.send_text(from_wxid, self.config["messages"]["download_error"])
|
||||
return {"success": False, "message": "视频下载失败"}
|
||||
|
||||
# 发送视频
|
||||
success = await bot.send_file(from_wxid, video_path)
|
||||
|
||||
if success:
|
||||
logger.success(f"随机视频发送成功: {from_wxid}")
|
||||
# 延迟删除,等待微信上传完成
|
||||
import asyncio
|
||||
asyncio.create_task(self._delayed_cleanup(video_path, 120))
|
||||
return {"success": True, "message": "随机视频发送成功"}
|
||||
else:
|
||||
await bot.send_text(from_wxid, self.config["messages"]["send_error"])
|
||||
# 立即删除失败的文件
|
||||
try:
|
||||
Path(video_path).unlink()
|
||||
except:
|
||||
pass
|
||||
return {"success": False, "message": "视频发送失败"}
|
||||
else:
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"LLM工具执行失败: {e}")
|
||||
return {"success": False, "message": f"执行失败: {str(e)}"}
|
||||
Reference in New Issue
Block a user