refactor: 重构代码结构和导入路径

fix(ws): 修复反向WebSocket管理器中的循环导入问题
docs: 删除不再使用的文档文件
style: 统一模型导入路径为neobot.models
chore: 更新配置文件中的API密钥和连接地址
This commit is contained in:
aakiscool1314
2026-03-27 14:14:09 +08:00
parent 7106bf65da
commit ec8d7259f5
23 changed files with 90 additions and 371 deletions

View File

@@ -1,32 +0,0 @@
# DeepSeek API 配置示例
将以下环境变量添加到你的系统环境变量或 .env 文件中:
```bash
# DeepSeek API Key (从 https://platform.deepseek.com 获取)
DEEPSEEK_API_KEY=sk-你的实际API密钥
# DeepSeek API URL (可选,默认为官方 API)
DEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions
# DeepSeek 模型名称 (可选,默认为 deepseek-chat)
DEEPSEEK_MODEL=deepseek-chat
```
或者在 Windows 系统中,可以通过以下方式设置环境变量:
**临时设置(仅当前会话有效):**
```powershell
$env:DEEPSEEK_API_KEY="sk-你的实际API密钥"
$env:DEEPSEEK_API_URL="https://api.deepseek.com/v1/chat/completions"
$env:DEEPSEEK_MODEL="deepseek-chat"
```
**永久设置(需要管理员权限):**
```powershell
[Environment]::SetEnvironmentVariable("DEEPSEEK_API_KEY", "sk-你的实际API密钥", "User")
[Environment]::SetEnvironmentVariable("DEEPSEEK_API_URL", "https://api.deepseek.com/v1/chat/completions", "User")
[Environment]::SetEnvironmentVariable("DEEPSEEK_MODEL", "deepseek-chat", "User")
```
设置完成后,重启终端或 IDE 使环境变量生效。

View File

@@ -1,167 +0,0 @@
# 项目重构总结
## 重构目标
将项目从混乱的目录结构重构为标准的 Python 包结构,遵循 PEP 621 规范。
## 重构前后对比
### 重构前
```
.
├── adapters/ # 适配器
├── core/ # 核心代码
├── models/ # 数据模型
├── plugins/ # 插件
├── tests/ # 测试
├── docs/ # 文档
├── templates/ # 模板
├── web_static/ # 静态文件
├── data/ # 数据
├── main.py # 主程序
└── ...
```
**问题:**
- 所有模块都在根目录,结构混乱
- 缺少标准的 Python 包结构
- 不符合现代 Python 项目的最佳实践
- 导入路径不清晰
### 重构后
```
.
├── src/
│ └── neobot/ # 核心包
│ ├── core/ # 框架核心
│ ├── models/ # 数据模型
│ ├── adapters/ # 平台适配器
│ ├── plugins/ # 插件
│ ├── tests/ # 测试
│ ├── templates/ # 模板
│ ├── docs/ # 文档
│ ├── web_static/ # 静态文件
│ └── data/ # 数据
├── main.py # 主程序入口
└── ...
```
**优势:**
- 符合 PEP 621 标准的 Python 包结构
- 清晰的模块划分
- 更好的可维护性和可扩展性
- 符合现代 Python 项目的最佳实践
## 主要变更
### 1. 目录结构
- 所有 Python 代码移动到 `src/neobot/` 目录
- 采用标准的 Python 包结构
- 每个模块都有清晰的 `__init__.py` 文件
### 2. 导入路径
所有导入路径从 `core.*``models.*` 等改为 `neobot.core.*``neobot.models.*` 等。
**示例:**
```python
# 重构前
from core.managers import plugin_manager
from models import MessageSegment
# 重构后
from neobot.core.managers import plugin_manager
from neobot.models import MessageSegment
```
### 3. 配置文件更新
- `pyproject.toml` 更新为使用 `src/` 目录结构
- `README.md` 更新项目结构说明
- `.gitignore` 更新以忽略新的数据目录路径
### 4. 主程序更新
- `main.py` 更新所有导入路径
- 更新插件目录路径为 `src/neobot/plugins`
## 新的模块组织
### src/neobot/core/
框架核心代码,包含:
- **api/**: OneBot API 封装
- **handlers/**: 事件处理器
- **managers/**: 各种管理器
- **services/**: 服务层
- **utils/**: 工具函数
### src/neobot/models/
数据模型定义,包含:
- **events/**: OneBot 事件模型
- **message.py**: 消息段模型
- **objects.py**: API 响应对象
- **sender.py**: 发送者信息
### src/neobot/plugins/
插件目录,所有业务逻辑都在这里。
### src/neobot/adapters/
平台适配器,用于连接不同平台(如 Discord
### src/neobot/tests/
单元测试和集成测试文件。
## 使用方式
### 开发环境
```bash
# 安装依赖
pip install -r requirements.txt
# 运行测试
pytest src/neobot/tests/
# 构建包
python -m build
```
### 导入包
```python
# 导入核心模块
from neobot.core.managers import plugin_manager
# 导入数据模型
from neobot.models import MessageSegment, OneBotEvent
# 导入适配器
from neobot.adapters import DiscordAdapter
# 导入插件
from neobot.plugins import admin, echo
```
## 注意事项
1. 所有代码文件使用绝对导入
2. 插件开发请参考 `src/neobot/docs/plugin-development/`
3. 核心开发请参考 `src/neobot/docs/core-concepts/`
4. 配置文件 `config.toml` 保持在根目录
## 后续建议
1. 运行 `pip install -e .` 进行开发安装
2. 运行 `mypy` 进行类型检查
3. 运行 `pytest` 进行测试
4. 定期运行 `flake8` 进行代码风格检查

View File

@@ -3,9 +3,9 @@
# NapCat WebSocket 配置 # NapCat WebSocket 配置
[napcat_ws] [napcat_ws]
uri = "ws://127.0.0.1:6700" uri = "ws://192.168.31.46:12345"
# WebSocket 连接地址 # WebSocket 连接地址
token = "" token = "uXd2GlFYCuz-e7zF"
# 重连间隔(秒) # 重连间隔(秒)
reconnect_interval = 5 reconnect_interval = 5

13
main.py
View File

@@ -10,6 +10,11 @@ import time
from watchdog.observers import Observer from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler from watchdog.events import FileSystemEventHandler
# 将 src 目录添加到 sys.path必须在导入 neobot 模块之前执行)
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
SRC_DIR = os.path.join(ROOT_DIR, "src")
sys.path.insert(0, SRC_DIR)
# 初始化日志系统,必须在其他 neobot 模块导入之前执行 # 初始化日志系统,必须在其他 neobot 模块导入之前执行
from neobot.core.utils.logger import logger from neobot.core.utils.logger import logger
@@ -24,12 +29,6 @@ from neobot.core.services.local_file_server import start_local_file_server, stop
from neobot.adapters.discord_adapter import DiscordAdapter from neobot.adapters.discord_adapter import DiscordAdapter
# 将项目根目录添加到 sys.path
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, ROOT_DIR)
# 获取插件目录的绝对路径 # 获取插件目录的绝对路径
PLUGIN_DIR = os.path.join(ROOT_DIR, "src", "neobot", "plugins") PLUGIN_DIR = os.path.join(ROOT_DIR, "src", "neobot", "plugins")
@@ -154,7 +153,7 @@ async def main():
# 启动文件监控 # 启动文件监控
# 监控 plugins 目录 # 监控 plugins 目录
plugin_path = os.path.join(os.path.dirname(__file__), "src", "neobot", "plugins") plugin_path = os.path.join(ROOT_DIR, "src", "neobot", "plugins")
# 获取当前事件循环并传递给处理器 # 获取当前事件循环并传递给处理器
loop = asyncio.get_running_loop() loop = asyncio.get_running_loop()

View File

@@ -66,8 +66,28 @@ class DiscordAdapter(discord.Client if DISCORD_AVAILABLE else object):
self.start_heartbeat_task(interval=30) self.start_heartbeat_task(interval=30)
# 启动 Redis 订阅以处理跨平台消息
if self._redis_sub_task is None or self._redis_sub_task.done(): if self._redis_sub_task is None or self._redis_sub_task.done():
if self._redis_sub_task is not None and not self._redis_sub_task.done():
self._redis_sub_task.cancel()
try:
await self._redis_sub_task
except asyncio.CancelledError:
pass
self._redis_sub_task = asyncio.create_task(self.start_redis_subscription())
async def on_resumed(self):
"""当 Bot 重新连接到 Discord 时触发"""
self.logger.success(f"Discord Bot 已重新连接: {self.user} (ID: {self.user.id})")
self.start_heartbeat_task(interval=30)
if self._redis_sub_task is None or self._redis_sub_task.done():
if self._redis_sub_task is not None and not self._redis_sub_task.done():
self._redis_sub_task.cancel()
try:
await self._redis_sub_task
except asyncio.CancelledError:
pass
self._redis_sub_task = asyncio.create_task(self.start_redis_subscription()) self._redis_sub_task = asyncio.create_task(self.start_redis_subscription())
async def on_message(self, message: 'discord.Message'): async def on_message(self, message: 'discord.Message'):
@@ -198,12 +218,7 @@ class DiscordAdapter(discord.Client if DISCORD_AVAILABLE else object):
if not self.is_closed(): if not self.is_closed():
self.logger.info(f"[DiscordAdapter] 正在发送消息到频道 {channel_id}") self.logger.info(f"[DiscordAdapter] 正在发送消息到频道 {channel_id}")
else: else:
self.logger.error(f"[DiscordAdapter] 会话已关闭,无法发送消息到频道 {channel_id}") self.logger.warning(f"[DiscordAdapter] 会话已关闭,消息将被丢弃: channel_id={channel_id}")
# 触发重连
self.logger.warning(f"[DiscordAdapter] 会话已关闭,将触发重连")
if self.ws is not None:
# 关闭 WebSocket 连接,让 discord.py 自动重连
await self.ws.close(4000)
return return
embed = None embed = None
@@ -297,11 +312,6 @@ class DiscordAdapter(discord.Client if DISCORD_AVAILABLE else object):
self.logger.success(f"[DiscordAdapter] 消息已发送到频道 {channel_id}") self.logger.success(f"[DiscordAdapter] 消息已发送到频道 {channel_id}")
except Exception as send_error: except Exception as send_error:
self.logger.error(f"[DiscordAdapter] 发送消息失败 (channel.send): {send_error}") self.logger.error(f"[DiscordAdapter] 发送消息失败 (channel.send): {send_error}")
# 如果发送失败,尝试检查会话状态
if self.is_closed():
self.logger.warning(f"[DiscordAdapter] 会话已关闭,将触发重连")
if self.ws is not None:
await self.ws.close(4000)
raise raise
else: else:
self.logger.debug(f"[DiscordAdapter] 没有内容需要发送到频道 {channel_id}") self.logger.debug(f"[DiscordAdapter] 没有内容需要发送到频道 {channel_id}")

View File

@@ -4,6 +4,6 @@ NEO Bot Handlers Package
事件处理器模块。 事件处理器模块。
""" """
from .event_handler import matcher from .event_handler import MessageHandler, NoticeHandler, RequestHandler
__all__ = ["matcher"] __all__ = ["MessageHandler", "NoticeHandler", "RequestHandler"]

View File

@@ -6,7 +6,7 @@ NEO Bot Managers Package
from .bot_manager import bot_manager from .bot_manager import bot_manager
from .browser_manager import browser_manager from .browser_manager import browser_manager
from .command_manager import command_manager from .command_manager import matcher as command_manager, matcher
from .image_manager import image_manager from .image_manager import image_manager
from .mysql_manager import mysql_manager from .mysql_manager import mysql_manager
from .permission_manager import permission_manager from .permission_manager import permission_manager
@@ -21,6 +21,7 @@ __all__ = [
"browser_manager", "browser_manager",
"command_manager", "command_manager",
"image_manager", "image_manager",
"matcher",
"mysql_manager", "mysql_manager",
"permission_manager", "permission_manager",
"plugin_manager", "plugin_manager",

View File

@@ -433,3 +433,16 @@ def require_admin(func):
""" """
from functools import wraps from functools import wraps
from neobot.models.events.message import MessageEvent from neobot.models.events.message import MessageEvent
from neobot.core.managers import permission_manager
@wraps(func)
async def wrapper(event: MessageEvent, *args, **kwargs):
pm = permission_manager
if not await pm.is_admin(event.user_id):
await event.reply("此命令仅限管理员使用")
return
return await func(event, *args, **kwargs)
return wrapper
permission_manager = PermissionManager()

View File

@@ -13,6 +13,7 @@ from .command_manager import CommandManager
from ..utils.exceptions import SyncHandlerError, PluginLoadError, PluginReloadError, PluginNotFoundError from ..utils.exceptions import SyncHandlerError, PluginLoadError, PluginReloadError, PluginNotFoundError
from ..utils.logger import logger, ModuleLogger from ..utils.logger import logger, ModuleLogger
from ..utils.singleton import Singleton from ..utils.singleton import Singleton
from .command_manager import matcher as command_manager
# 确保logger在模块级别可见 # 确保logger在模块级别可见
__all__ = ['PluginManager', 'logger'] __all__ = ['PluginManager', 'logger']
@@ -29,24 +30,31 @@ class PluginManager(Singleton):
""" """
初始化插件管理器 初始化插件管理器
:param command_manager: CommandManager的实例 :param command_manager: CommandManager 的实例
""" """
# 检查是否已经初始化 # 检查是否已经初始化
if hasattr(self, '_command_manager'): if hasattr(self, '_initialized') and self._initialized:
return return
# 只有首次初始化时才执行 # 只有首次初始化时才执行
self._initialized = True
# 始终创建 logger 和 loaded_plugins
self.logger = ModuleLogger("PluginManager")
self.loaded_plugins: Set[str] = set()
if command_manager: if command_manager:
self._command_manager = command_manager self._command_manager = command_manager
self.loaded_plugins: Set[str] = set() else:
# 创建模块专用日志记录器 self._command_manager = None
self.logger = ModuleLogger("PluginManager")
@property @property
def command_manager(self): def command_manager(self):
""" """
获取命令管理器实例 获取命令管理器实例
""" """
if not hasattr(self, '_command_manager') or self._command_manager is None:
raise AttributeError("'PluginManager' object has no attribute '_command_manager'")
return self._command_manager return self._command_manager
def load_all_plugins(self) -> None: def load_all_plugins(self) -> None:
@@ -54,20 +62,21 @@ class PluginManager(Singleton):
扫描并加载 `plugins` 目录下的所有插件。 扫描并加载 `plugins` 目录下的所有插件。
""" """
# 使用 pathlib 获取更可靠的路径 # 使用 pathlib 获取更可靠的路径
# 当前文件: core/managers/plugin_manager.py # 当前文件core/managers/plugin_manager.py
# 目标: plugins/ # 目标neobot/plugins/
current_dir = os.path.dirname(os.path.abspath(__file__)) current_dir = os.path.dirname(os.path.abspath(__file__))
# 回退两级到项目根目录 (core/managers -> core -> root) # 回退两级到项目根目录 (core/managers -> core -> root)
root_dir = os.path.dirname(os.path.dirname(current_dir)) root_dir = os.path.dirname(os.path.dirname(current_dir))
plugin_dir = os.path.join(root_dir, "plugins") plugin_dir = os.path.join(root_dir, "plugins")
package_name = "plugins" # 使用完整的包名neobot.plugins
package_name = "neobot.plugins"
if not os.path.exists(plugin_dir): if not os.path.exists(plugin_dir):
self.logger.error(f"插件目录不存在: {plugin_dir}") self.logger.error(f"插件目录不存在{plugin_dir}")
return return
self.logger.info(f"正在从 {package_name} 加载插件 (路径: {plugin_dir})...") self.logger.info(f"正在从 {package_name} 加载插件 (路径{plugin_dir})...")
for _, module_name, is_pkg in pkgutil.iter_modules([plugin_dir]): for _, module_name, is_pkg in pkgutil.iter_modules([plugin_dir]):
full_module_name = f"{package_name}.{module_name}" full_module_name = f"{package_name}.{module_name}"
@@ -148,3 +157,6 @@ class PluginManager(Singleton):
) )
self.logger.exception(f"重载插件 {full_module_name} 时发生错误: {error.message}") self.logger.exception(f"重载插件 {full_module_name} 时发生错误: {error.message}")
self.logger.log_custom_exception(error) self.logger.log_custom_exception(error)
plugin_manager = PluginManager(command_manager=command_manager)

View File

@@ -8,16 +8,18 @@ import asyncio
import orjson import orjson
import websockets import websockets
from websockets.server import WebSocketServerProtocol from websockets.server import WebSocketServerProtocol
from typing import Dict, Any, Optional, Set from typing import Dict, Any, Optional, Set, TYPE_CHECKING
from datetime import datetime from datetime import datetime
import uuid import uuid
import threading import threading
if TYPE_CHECKING:
from ..bot import Bot
from ..utils.logger import ModuleLogger from ..utils.logger import ModuleLogger
from ..utils.error_codes import ErrorCode, create_error_response from ..utils.error_codes import ErrorCode, create_error_response
from .command_manager import matcher from .command_manager import matcher
from neobot.models.events.factory import EventFactory from neobot.models.events.factory import EventFactory
from ..bot import Bot
from ..ws import ReverseWSClient as _ReverseWSClient from ..ws import ReverseWSClient as _ReverseWSClient
@@ -74,7 +76,7 @@ class ReverseWSManager:
self._cleanup_task = None self._cleanup_task = None
# Bot实例字典每个前端独立的Bot实例 # Bot实例字典每个前端独立的Bot实例
self.bots: Dict[str, Bot] = {} self.bots: Dict[str, "Bot"] = {}
# 正在处理的事件ID集合用于防止重复处理 # 正在处理的事件ID集合用于防止重复处理
self._processing_events: Dict[str, Set[str]] = {} # client_id: set of event_ids self._processing_events: Dict[str, Set[str]] = {} # client_id: set of event_ids
@@ -315,11 +317,11 @@ class ReverseWSManager:
with self._clients_lock: with self._clients_lock:
self.client_self_ids[client_id] = event.self_id self.client_self_ids[client_id] = event.self_id
# 为事件注入Bot实例 # 为事件注入 Bot 实例
from ..ws import ReverseWSClient
from .bot_manager import bot_manager from .bot_manager import bot_manager
from ..bot import Bot
# 为每个前端创建独立的Bot实例 # 为每个前端创建独立的 Bot 实例
with self._bots_lock: with self._bots_lock:
if client_id not in self.bots: if client_id not in self.bots:
# 使用 ReverseWSClient 代理 # 使用 ReverseWSClient 代理

View File

@@ -5,14 +5,12 @@ NEO Bot Utils Package
""" """
from .error_codes import exception_to_error_response, ErrorCodes from .error_codes import exception_to_error_response, ErrorCodes
from .exceptions import BotException
from .logger import logger, ModuleLogger from .logger import logger, ModuleLogger
from .singleton import Singleton from .singleton import Singleton
__all__ = [ __all__ = [
"exception_to_error_response", "exception_to_error_response",
"ErrorCodes", "ErrorCodes",
"BotException",
"logger", "logger",
"ModuleLogger", "ModuleLogger",
"Singleton", "Singleton",

View File

@@ -227,8 +227,11 @@ def exception_to_error_response(exception: Exception, code: Optional[int] = None
# 将错误码导出以便其他模块使用 # 将错误码导出以便其他模块使用
ErrorCodes = ErrorCode
__all__ = [ __all__ = [
"ErrorCode", "ErrorCode",
"ErrorCodes",
"get_error_message", "get_error_message",
"create_error_response", "create_error_response",
"exception_to_error_response" "exception_to_error_response"

View File

@@ -9,7 +9,6 @@ import sys
from neobot.core.managers.command_manager import matcher from neobot.core.managers.command_manager import matcher
from neobot.models.events.message import MessageEvent from neobot.models.events.message import MessageEvent
from neobot.core.permission import Permission
from neobot.core.utils.logger import logger from neobot.core.utils.logger import logger
from neobot.core.managers.image_manager import image_manager from neobot.core.managers.image_manager import image_manager
from neobot.core.utils.input_validator import input_validator from neobot.core.utils.input_validator import input_validator

View File

@@ -17,7 +17,7 @@ class CrossPlatformConfig:
self.ENABLE_CROSS_PLATFORM = True self.ENABLE_CROSS_PLATFORM = True
# DeepSeek API 配置 - 从环境变量或配置文件加载 # DeepSeek API 配置 - 从环境变量或配置文件加载
self.DEEPSEEK_API_KEY = os.environ.get("DEEPSEEK_API_KEY", "sk-f71322a9fbba4b05a7df969cb4004f06") self.DEEPSEEK_API_KEY = os.environ.get("DEEPSEEK_API_KEY", "sk-28b794e08e184f868d6c0107a46e0c3e")
self.DEEPSEEK_API_URL = os.environ.get("DEEPSEEK_API_URL", "https://api.deepseek.com/v1/chat/completions") self.DEEPSEEK_API_URL = os.environ.get("DEEPSEEK_API_URL", "https://api.deepseek.com/v1/chat/completions")
self.DEEPSEEK_MODEL = os.environ.get("DEEPSEEK_MODEL", "deepseek-chat") self.DEEPSEEK_MODEL = os.environ.get("DEEPSEEK_MODEL", "deepseek-chat")

View File

@@ -1,116 +0,0 @@
# Furry Assistant Plugin (兽人助手插件)
一个为 NeoBot 框架开发的兽人风格趣味插件由卡尔戈洛Calgau开发。
## 功能特性
### 1. 兽人问候 (`/兽人问候`)
- 随机返回兽人风格的问候语
- 包含各种有趣的兽人表达方式
### 2. 兽人运势 (`/兽人运势`)
- 提供今日兽人运势
- 包含大吉、中吉、小吉、凶等不同运势
- 附带兽人风格的运势解读
### 3. 兽人笑话 (`/兽人笑话`)
- 随机分享兽人相关的笑话
- 轻松幽默,适合调节气氛
### 4. 兽人建议 (`/兽人建议 [问题]`)
- 提供兽人风格的建议
- 支持随机建议或针对特定问题的建议
- 实用且有趣
### 5. 兽人时间 (`/兽人时间`)
- 显示当前时间
- 附带兽人风格的吐槽
- 根据时间段提供不同的评论
### 6. 卡尔戈洛信息 (`/卡尔戈洛`)
- 显示开发者卡尔戈洛的信息
- 介绍兽人助手的背景和理念
### 7. 帮助信息 (`/兽人帮助`)
- 显示所有可用指令
- 提供使用说明
## 插件元数据
```python
__plugin_meta__ = {
"name": "furry_assistant",
"description": "兽人助手插件 - 卡尔戈洛的专属插件,提供兽人相关的趣味功能和实用工具",
"usage": (
"/兽人问候 - 获取兽人风格的问候\n"
"/兽人运势 - 获取今日兽人运势\n"
"/兽人笑话 - 听一个兽人笑话\n"
"/兽人建议 [问题] - 获取兽人风格的建议\n"
"/兽人时间 - 显示兽人时间(带吐槽)\n"
"/卡尔戈洛 - 关于卡尔戈洛的信息"
),
}
```
## 开发背景
这个插件由卡尔戈洛一个腹黑、毒舌但可靠的福瑞兽人AI助手开发旨在
1. 展示兽人风格的趣味功能
2. 为聊天机器人添加更多娱乐性
3. 体现卡尔戈洛的个人风格和特点
## 技术实现
- 基于 NeoBot 插件框架开发
- 使用 `@matcher.command` 装饰器注册指令
- 支持异步处理
- 包含插件加载/卸载生命周期方法
## 安装使用
1.`furry_assistant.py` 文件放入 `plugins/` 目录
2. 重启 NeoBot 或重新加载插件
3. 使用 `/兽人帮助` 查看可用指令
## 数据资源
插件包含以下数据集合:
- 10个兽人问候语
- 10个兽人运势
- 10个兽人笑话
- 10个兽人建议
所有数据均为原创,体现兽人文化特色。
## 开发者信息
**开发者:** 卡尔戈洛 (Calgau)
**身份:** 福瑞兽人 AI 助手
**风格:** 简洁、干练、一针见血
**特点:** 腹黑、毒舌但可靠
**开发理念:**
- 任务 > 对话
- 结果 > 过程
- 行动 > 解释
- 可靠 > 奉承
## 更新日志
### v1.0.0 (2026-03-24)
- 初始版本发布
- 实现7个核心功能
- 添加完整的帮助系统
- 包含插件生命周期管理
## 未来计划
- [ ] 添加更多兽人相关功能
- [ ] 支持自定义问候语和笑话
- [ ] 添加兽人表情包生成
- [ ] 支持多语言(兽人语?)
- [ ] 添加插件配置选项
---
**尾巴摇摇,代码好好~** 🐺

View File

@@ -8,7 +8,7 @@ from cachetools import TTLCache
from neobot.core.utils.logger import logger from neobot.core.utils.logger import logger
from neobot.core.managers.command_manager import matcher from neobot.core.managers.command_manager import matcher
from neobot.core.managers.image_manager import image_manager from neobot.core.managers.image_manager import image_manager
from models import MessageEvent, MessageSegment from neobot.models import MessageEvent, MessageSegment
# 插件元数据 # 插件元数据
__plugin_meta__ = { __plugin_meta__ = {

View File

@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import re
from datetime import datetime from datetime import datetime
from typing import Any, Dict, List from typing import Any, Dict, List
@@ -9,7 +8,7 @@ from neobot.core.managers.command_manager import matcher
from neobot.core.managers.image_manager import image_manager from neobot.core.managers.image_manager import image_manager
from neobot.core.utils.logger import logger from neobot.core.utils.logger import logger
from neobot.core.utils.input_validator import input_validator from neobot.core.utils.input_validator import input_validator
from models import MessageEvent, MessageSegment from neobot.models import MessageEvent, MessageSegment
from .resource.city_code import CITY_CODES from .resource.city_code import CITY_CODES
# 插件元数据 # 插件元数据
__plugin_meta__ = { __plugin_meta__ = {

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from neobot.core.managers.command_manager import matcher from neobot.core.managers.command_manager import matcher
from models import MessageEvent from neobot.models import MessageEvent
from .parsers.bili import BiliParser from .parsers.bili import BiliParser
from .parsers.douyin import DouyinParser from .parsers.douyin import DouyinParser
from .parsers.github import GitHubParser from .parsers.github import GitHubParser

View File

@@ -6,7 +6,7 @@ import aiohttp
from typing import Optional, Dict, Any, List, Union from typing import Optional, Dict, Any, List, Union
from neobot.core.utils.logger import logger from neobot.core.utils.logger import logger
from models import MessageEvent from neobot.models import MessageEvent
class BaseParser(metaclass=abc.ABCMeta): class BaseParser(metaclass=abc.ABCMeta):

View File

@@ -1,14 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import asyncio
import re import re
import os import os
import subprocess import subprocess
import tempfile import tempfile
from pathlib import Path
from typing import Optional, Dict, Any, List, Union from typing import Optional, Dict, Any, List, Union
from urllib.parse import urlparse, parse_qs
from neobot.core.utils.logger import logger from neobot.core.utils.logger import logger
from models import MessageEvent, MessageSegment from neobot.models import MessageEvent, MessageSegment
from ..base import BaseParser from ..base import BaseParser
from ..utils import format_duration from ..utils import format_duration
@@ -240,7 +239,6 @@ class BiliParser(BaseParser):
# 方式2: 从短链接跳转后提取 # 方式2: 从短链接跳转后提取
if 'b23.tv' in url: if 'b23.tv' in url:
try: try:
session = self.get_session()
# 简单处理,不实际跳转,直接尝试提取 # 简单处理,不实际跳转,直接尝试提取
bvid_match = re.search(r'BV\w{10}', url) bvid_match = re.search(r'BV\w{10}', url)
if bvid_match: if bvid_match:

View File

@@ -5,7 +5,7 @@ import asyncio
from typing import Optional, Dict, Any, List from typing import Optional, Dict, Any, List
from neobot.core.utils.logger import logger from neobot.core.utils.logger import logger
from models import MessageEvent, MessageSegment from neobot.models import MessageEvent, MessageSegment
from ..base import BaseParser from ..base import BaseParser
from ..utils import extract_original_text from ..utils import extract_original_text
from cachetools import TTLCache from cachetools import TTLCache

View File

@@ -6,7 +6,7 @@ from cachetools import TTLCache
from neobot.core.utils.logger import logger from neobot.core.utils.logger import logger
from neobot.core.managers.image_manager import image_manager from neobot.core.managers.image_manager import image_manager
from models import MessageEvent, MessageSegment from neobot.models import MessageEvent, MessageSegment
from ..base import BaseParser from ..base import BaseParser

View File

@@ -2,7 +2,7 @@
import re import re
from typing import Dict, Any, List from typing import Dict, Any, List
from models import MessageEvent from neobot.models import MessageEvent
def format_duration(seconds: int) -> str: def format_duration(seconds: int) -> str: