190 lines
6.5 KiB
Python
190 lines
6.5 KiB
Python
"""
|
||
脚本管理模块
|
||
|
||
管理 Tavern Helper 的脚本,支持三种作用域:
|
||
- GLOBAL: 全局脚本,对所有聊天可用
|
||
- CHARACTER: 角色脚本,绑定到当前角色卡
|
||
- PRESET: 预设脚本,绑定到当前预设
|
||
|
||
每个脚本包含:
|
||
- 脚本名称
|
||
- 脚本内容(JavaScript 代码)
|
||
- 作者备注
|
||
- 变量列表(绑定到脚本的变量)
|
||
- 按钮配置(配合 getButtonEvent 使用)
|
||
- 启用状态
|
||
"""
|
||
from enum import Enum
|
||
from typing import List, Optional, Dict, Any
|
||
from pydantic import BaseModel, Field
|
||
from datetime import datetime
|
||
import uuid
|
||
|
||
|
||
class ScriptScope(str, Enum):
|
||
"""脚本作用域"""
|
||
GLOBAL = 'global' # 全局脚本
|
||
CHARACTER = 'character' # 角色脚本
|
||
PRESET = 'preset' # 预设脚本
|
||
|
||
|
||
class ScriptVariable(BaseModel):
|
||
"""脚本变量"""
|
||
name: str = Field(..., description="变量名")
|
||
value: Any = Field(..., description="变量值")
|
||
description: Optional[str] = Field(None, description="变量描述")
|
||
|
||
|
||
class ScriptButton(BaseModel):
|
||
"""脚本按钮配置"""
|
||
label: str = Field(..., description="按钮显示文本")
|
||
event: str = Field(..., description="按钮事件名称(配合 getButtonEvent 使用)")
|
||
enabled: bool = Field(True, description="是否启用")
|
||
|
||
|
||
class ScriptItem(BaseModel):
|
||
"""脚本项"""
|
||
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="脚本唯一标识符")
|
||
name: str = Field(..., description="脚本名称")
|
||
content: str = Field(..., description="脚本内容(JavaScript 代码)")
|
||
authorNote: Optional[str] = Field(None, description="作者备注")
|
||
|
||
# 变量列表
|
||
variables: List[ScriptVariable] = Field(default_factory=list, description="绑定到脚本的变量")
|
||
|
||
# 按钮配置
|
||
buttons: List[ScriptButton] = Field(default_factory=list, description="按钮配置")
|
||
|
||
# 作用域
|
||
scope: ScriptScope = Field(ScriptScope.GLOBAL, description="脚本作用域")
|
||
characterName: Optional[str] = Field(None, description="绑定的角色卡名称")
|
||
presetName: Optional[str] = Field(None, description="绑定的预设名称")
|
||
|
||
# 启用状态
|
||
enabled: bool = Field(True, description="是否启用")
|
||
|
||
# 元数据
|
||
createdAt: int = Field(default_factory=lambda: int(datetime.now().timestamp()), description="创建时间戳")
|
||
updatedAt: int = Field(default_factory=lambda: int(datetime.now().timestamp()), description="更新时间戳")
|
||
order: int = Field(0, description="执行顺序")
|
||
|
||
|
||
class ScriptManager:
|
||
"""脚本管理器"""
|
||
|
||
def __init__(self):
|
||
self.scripts: List[ScriptItem] = []
|
||
|
||
def add_script(self, script: ScriptItem):
|
||
"""添加脚本"""
|
||
self.scripts.append(script)
|
||
|
||
def remove_script(self, script_id: str) -> bool:
|
||
"""删除脚本"""
|
||
for i, script in enumerate(self.scripts):
|
||
if script.id == script_id:
|
||
self.scripts.pop(i)
|
||
return True
|
||
return False
|
||
|
||
def update_script(self, script_id: str, updates: Dict[str, Any]) -> bool:
|
||
"""更新脚本"""
|
||
for script in self.scripts:
|
||
if script.id == script_id:
|
||
for key, value in updates.items():
|
||
if hasattr(script, key):
|
||
setattr(script, key, value)
|
||
script.updatedAt = int(datetime.now().timestamp())
|
||
return True
|
||
return False
|
||
|
||
def get_scripts_by_scope(self, scope: ScriptScope, filter_name: Optional[str] = None) -> List[ScriptItem]:
|
||
"""按作用域获取脚本"""
|
||
scripts = [s for s in self.scripts if s.scope == scope]
|
||
|
||
if filter_name:
|
||
scripts = [s for s in scripts if filter_name.lower() in s.name.lower()]
|
||
|
||
return sorted(scripts, key=lambda s: s.order)
|
||
|
||
def get_enabled_scripts(self, scope: ScriptScope) -> List[ScriptItem]:
|
||
"""获取启用的脚本"""
|
||
return [s for s in self.scripts if s.scope == scope and s.enabled]
|
||
|
||
def get_script(self, script_id: str) -> Optional[ScriptItem]:
|
||
"""获取单个脚本"""
|
||
for script in self.scripts:
|
||
if script.id == script_id:
|
||
return script
|
||
return None
|
||
|
||
def toggle_script(self, script_id: str) -> bool:
|
||
"""切换脚本启用状态"""
|
||
for script in self.scripts:
|
||
if script.id == script_id:
|
||
script.enabled = not script.enabled
|
||
script.updatedAt = int(datetime.now().timestamp())
|
||
return True
|
||
return False
|
||
|
||
def get_all_scripts(self) -> List[ScriptItem]:
|
||
"""获取所有脚本"""
|
||
return self.scripts
|
||
|
||
def export_scripts(self, scope: Optional[ScriptScope] = None) -> List[Dict]:
|
||
"""导出脚本"""
|
||
if scope:
|
||
scripts = [s for s in self.scripts if s.scope == scope]
|
||
else:
|
||
scripts = self.scripts
|
||
|
||
return [s.dict() for s in scripts]
|
||
|
||
def import_scripts(self, scripts_data: List[Dict], scope: ScriptScope) -> int:
|
||
"""导入脚本"""
|
||
count = 0
|
||
for data in scripts_data:
|
||
try:
|
||
script = ScriptItem(**data)
|
||
script.scope = scope
|
||
self.scripts.append(script)
|
||
count += 1
|
||
except Exception as e:
|
||
print(f"导入脚本失败: {e}")
|
||
|
||
return count
|
||
|
||
|
||
# 全局脚本管理器实例
|
||
script_manager = ScriptManager()
|
||
|
||
|
||
if __name__ == '__main__':
|
||
import json
|
||
|
||
# 测试脚本管理
|
||
manager = ScriptManager()
|
||
|
||
# 添加测试脚本
|
||
script1 = ScriptItem(
|
||
name="【骰子系统】-自动更新",
|
||
content="async function getLatestVersion() {\n try {\n const response = await fetch('/api/version');\n return await response.json();\n } catch (e) {\n return null;\n }\n}",
|
||
authorNote="感谢a佬开源\n以九颜二改为基础进行三改\n@kousakayou",
|
||
scope=ScriptScope.GLOBAL,
|
||
variables=[
|
||
ScriptVariable(name="version", value="4.8.4", description="版本号")
|
||
],
|
||
buttons=[
|
||
ScriptButton(label="检查更新", event="checkUpdate", enabled=True)
|
||
]
|
||
)
|
||
|
||
manager.add_script(script1)
|
||
|
||
# 导出测试
|
||
print("=== 导出脚本 ===")
|
||
exported = manager.export_scripts()
|
||
print(json.dumps(exported, indent=2, ensure_ascii=False))
|
||
|
||
print("\n✅ 脚本管理测试完成!")
|