mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-05-08 14:23:27 +08:00
105 lines
4.8 KiB
Python
105 lines
4.8 KiB
Python
"""更新自定义识别词工具"""
|
|
|
|
import json
|
|
from typing import List, Optional, Type
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
from app.agent.tools.base import MoviePilotTool
|
|
from app.db.systemconfig_oper import SystemConfigOper
|
|
from app.log import logger
|
|
from app.schemas.types import SystemConfigKey
|
|
|
|
|
|
class UpdateCustomIdentifiersInput(BaseModel):
|
|
"""更新自定义识别词工具的输入参数模型"""
|
|
|
|
explanation: str = Field(
|
|
...,
|
|
description="Clear explanation of why this tool is being used in the current context",
|
|
)
|
|
identifiers: List[str] = Field(
|
|
...,
|
|
description=(
|
|
"The complete list of custom identifier rules to save. "
|
|
"This REPLACES the entire existing list. "
|
|
"Always query existing identifiers first, merge new rules, then pass the full list. "
|
|
"These rules are global and affect future recognition for all torrents/files. "
|
|
"When adding a rule for a user-provided sample, prefer narrow regex patterns that include "
|
|
"sample-specific anchors such as the title alias, year, season/episode marker, group tag, "
|
|
"resolution, or other distinctive fragments. Avoid overly broad patterns like bare generic "
|
|
"tags, pure episode numbers, or common release words unless the user explicitly wants a global rule."
|
|
),
|
|
)
|
|
|
|
|
|
class UpdateCustomIdentifiersTool(MoviePilotTool):
|
|
name: str = "update_custom_identifiers"
|
|
description: str = (
|
|
"Update the full list of custom identifiers (自定义识别词) used for preprocessing torrent/file names. "
|
|
"This tool REPLACES all existing identifier rules with the provided list. "
|
|
"IMPORTANT: Always use 'query_custom_identifiers' first to get existing rules, "
|
|
"then merge new rules into the list before calling this tool to avoid accidentally deleting existing rules. "
|
|
"IMPORTANT: New identifier rules are global. When the rule is created from a specific torrent/file name, "
|
|
"make the regex as narrow as possible and include distinctive elements from that sample so unrelated titles "
|
|
"are not affected. Prefer contextual replacements with capture groups/backreferences over bare block words "
|
|
"when a generic word like REPACK, WEB-DL, 1080p, 字幕, or a simple episode marker would otherwise match too broadly. "
|
|
"Supported rule formats (spaces around operators are required): "
|
|
"1) Block word: just the word/regex to remove; "
|
|
"2) Replacement: '被替换词 => 替换词'; "
|
|
"3) Episode offset: '前定位词 <> 后定位词 >> EP±N'; "
|
|
"4) Combined: '被替换词 => 替换词 && 前定位词 <> 后定位词 >> EP±N'; "
|
|
"Lines starting with '#' are comments. "
|
|
"The replacement target supports: {[tmdbid=xxx;type=movie/tv;s=xxx;e=xxx]} for direct TMDB ID matching."
|
|
)
|
|
args_schema: Type[BaseModel] = UpdateCustomIdentifiersInput
|
|
|
|
def get_tool_message(self, **kwargs) -> Optional[str]:
|
|
"""生成友好的提示消息"""
|
|
identifiers = kwargs.get("identifiers", [])
|
|
return f"更新自定义识别词(共 {len(identifiers)} 条规则)"
|
|
|
|
async def run(self, identifiers: List[str] = None, **kwargs) -> str:
|
|
logger.info(
|
|
f"执行工具: {self.name}, 规则数量: {len(identifiers) if identifiers else 0}"
|
|
)
|
|
try:
|
|
if identifiers is None:
|
|
return json.dumps(
|
|
{"success": False, "message": "必须提供 identifiers 参数"},
|
|
ensure_ascii=False,
|
|
)
|
|
|
|
# 过滤空字符串
|
|
identifiers = [i for i in identifiers if i is not None]
|
|
|
|
system_config_oper = SystemConfigOper()
|
|
|
|
# 保存
|
|
value = identifiers if identifiers else None
|
|
success = await system_config_oper.async_set(
|
|
SystemConfigKey.CustomIdentifiers, value
|
|
)
|
|
if success:
|
|
return json.dumps(
|
|
{
|
|
"success": True,
|
|
"message": f"自定义识别词已更新,共 {len(identifiers)} 条规则",
|
|
"count": len(identifiers),
|
|
"identifiers": identifiers,
|
|
},
|
|
ensure_ascii=False,
|
|
indent=2,
|
|
)
|
|
else:
|
|
return json.dumps(
|
|
{"success": False, "message": "保存自定义识别词失败"},
|
|
ensure_ascii=False,
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"更新自定义识别词失败: {e}")
|
|
return json.dumps(
|
|
{"success": False, "message": f"更新自定义识别词时发生错误: {str(e)}"},
|
|
ensure_ascii=False,
|
|
)
|