feat(video-analysis): 群策略 v3 / 群文件投递通道 / Web 管理页
- policy.py:per-group 正交策略(自动解析 / 自动策略 / 禁用策略 / 存储 A·B·C /
公网 / 链接 / 群文件 + 平台限定),list.json v1/v2 → v3 自动迁移,
写入统一走 PolicyStore(加锁 + .tmp 原子替换 + 字段归一)
- 群文件并行通道 group_file.py:打包 zip(可选 pyzipper AES-256)后优先走 S3 预签名、
本地直传兜底;设了密码但 pyzipper 不可用就放弃上传,不退化成明文
- list_proc.py 收敛到「视频策略」统一入口,权限判定改走 policy
- Web 管理页 /hub/video_analysis(群策略 + 链接解析面板)与 services/web_jobs.py
(只复用纯函数层,Web 上下文不发消息;内存任务表 + 并发闸门 + 超时)
- 媒体命名统一到 utils.py({作者}_{作者id}/{作品名}[_短码]),cleanup 回收空目录
- 测试:policy / 命名 / 群文件 / web_jobs 四组
顺带 pyproject 的 pytest 加 testpaths=tests(避免收进 debug/ 下的调试脚本)。
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -1,21 +1,48 @@
|
||||
"""统一配置注册:把插件配置按文档标准接入 hexi.web_hub.web_config(Web 可读可改)。
|
||||
|
||||
- temp 清理配置(env pydantic) → register_model_config
|
||||
- 群文件投递配置(打包/解压密码, env pydantic) → register_model_config
|
||||
- S3 存储配置(原硬编码在 services/storage/s3.py) → register_config_items(store=s3 模块)
|
||||
- 群分组配置(data/list.json) → register_config_items(type=json, nosave)
|
||||
|
||||
群策略(data/list.json v3)不在这里注册:它有独立的 Web 页面与 API
|
||||
(见 web_hub.py),不再走配置抽屉里的裸 JSON 编辑。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from nonebot import get_plugin_config
|
||||
from pydantic import BaseModel
|
||||
|
||||
from hexi.web_hub.config_standard import register_config_items, register_model_config
|
||||
|
||||
from . import cleanup, list_proc # noqa: F401
|
||||
from . import cleanup # noqa: F401
|
||||
from .services.storage import s3 as _s3mod
|
||||
|
||||
# 插件模块名 = plugin_id(与 NoneBot 模块名一致)
|
||||
_PLUGIN_ID = __package__
|
||||
|
||||
|
||||
class GroupFileConfig(BaseModel):
|
||||
# 上传群文件时打包成一个 zip(关掉则逐个上传原文件)
|
||||
video_analysis_group_file_zip: bool = True
|
||||
# 压缩包解压密码(留空 = 不加密; 设置后要求 pyzipper 可用, 否则放弃群文件上传)
|
||||
video_analysis_group_file_password: str = ""
|
||||
|
||||
|
||||
group_file_config = get_plugin_config(GroupFileConfig)
|
||||
|
||||
|
||||
def group_file_settings() -> tuple[bool, str]:
|
||||
"""群文件投递设置:(是否打包成 zip, 解压密码)。
|
||||
|
||||
运行期读取实例属性,所以 Web 保存后立即生效(apply 是 setattr)。
|
||||
"""
|
||||
return (
|
||||
bool(group_file_config.video_analysis_group_file_zip),
|
||||
str(group_file_config.video_analysis_group_file_password or ""),
|
||||
)
|
||||
|
||||
|
||||
def _reset_s3_caches(_values=None, store=None):
|
||||
"""保存 S3 配置后清空懒加载客户端缓存,让下次上传用新配置重建。"""
|
||||
if store is None:
|
||||
@@ -59,7 +86,29 @@ def register_config() -> None:
|
||||
apply_extra=lambda _values, _conf: cleanup.reload_cleanup_config(),
|
||||
)
|
||||
|
||||
# 2) S3 存储配置(来源无关)
|
||||
# 2) 群文件投递:打包 / 解压密码
|
||||
register_model_config(
|
||||
_PLUGIN_ID,
|
||||
group_file_config,
|
||||
fields=[
|
||||
"video_analysis_group_file_zip",
|
||||
"video_analysis_group_file_password",
|
||||
],
|
||||
labels={
|
||||
"video_analysis_group_file_zip": "群文件打包成 zip",
|
||||
"video_analysis_group_file_password": "压缩包解压密码",
|
||||
},
|
||||
descriptions={
|
||||
"video_analysis_group_file_zip": "开启后群文件收到的是一个压缩包;关闭则逐个上传原文件",
|
||||
"video_analysis_group_file_password": "留空 = 不加密;设置后用 AES-256 加密(需要 7-Zip/WinRAR 等工具解压),缺 pyzipper 时会放弃群文件上传而不是传明文",
|
||||
},
|
||||
types={
|
||||
"video_analysis_group_file_zip": "bool",
|
||||
"video_analysis_group_file_password": "password",
|
||||
},
|
||||
)
|
||||
|
||||
# 3) S3 存储配置(来源无关)
|
||||
register_config_items(
|
||||
_PLUGIN_ID,
|
||||
[
|
||||
@@ -86,19 +135,3 @@ def register_config() -> None:
|
||||
store=_s3mod,
|
||||
apply_extra=_reset_s3_caches,
|
||||
)
|
||||
|
||||
# 3) 群分组配置(data/list.json, 权威源在插件自身)
|
||||
register_config_items(
|
||||
_PLUGIN_ID,
|
||||
[
|
||||
{
|
||||
"key": "group_config",
|
||||
"label": "群分组配置",
|
||||
"type": "json",
|
||||
"description": "data/list.json 内容。groups 为 {群号: {auto, plan(A/B), auto_link[]}},blacklist 为禁用用户 QQ 列表。白名单即 groups 的键。",
|
||||
"getter": list_proc.get_group_config_sync,
|
||||
"setter": list_proc.set_group_config_sync,
|
||||
"nosave": True,
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user