feat:初版

This commit is contained in:
2025-12-03 15:48:44 +08:00
commit b4df26f61d
199 changed files with 23434 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
from .main import RandomVideo
__all__ = ["RandomVideo"]

226
plugins/RandomVideo/main.py Normal file
View 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)}"}