Files
MoviePilot/app/agent/tools/impl/modify_download.py
2026-04-28 20:36:49 +08:00

140 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""修改下载任务工具"""
from typing import Optional, Type, List
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.download import DownloadChain
from app.log import logger
class ModifyDownloadInput(BaseModel):
"""修改下载任务工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
hash: str = Field(
..., description="Task hash (can be obtained from query_download_tasks tool)"
)
action: Optional[str] = Field(
None,
description="Action to perform on the task: 'start' to resume downloading, 'stop' to pause downloading. "
"If not provided, no start/stop action will be performed.",
)
tags: Optional[List[str]] = Field(
None,
description="List of tags to set on the download task. If provided, these tags will be added to the task. "
"Example: ['movie', 'hd']",
)
downloader: Optional[str] = Field(
None,
description="Name of specific downloader (optional, if not provided will search all downloaders)",
)
class ModifyDownloadTool(MoviePilotTool):
"""修改下载任务工具"""
name: str = "modify_download"
description: str = (
"Modify a download task in the downloader by task hash. "
"Supports: 1) Setting tags on a download task, "
"2) Starting (resuming) a paused download task, "
"3) Stopping (pausing) a downloading task. "
"Multiple operations can be performed in a single call."
)
args_schema: Type[BaseModel] = ModifyDownloadInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
hash_value = kwargs.get("hash", "")
action = kwargs.get("action")
tags = kwargs.get("tags")
downloader = kwargs.get("downloader")
parts = [f"修改下载任务: {hash_value}"]
if action == "start":
parts.append("操作: 开始下载")
elif action == "stop":
parts.append("操作: 暂停下载")
if tags:
parts.append(f"标签: {', '.join(tags)}")
if downloader:
parts.append(f"下载器: {downloader}")
return " | ".join(parts)
@staticmethod
def _modify_download_sync(
hash_value: str,
action: Optional[str] = None,
tags: Optional[List[str]] = None,
downloader: Optional[str] = None,
) -> List[str]:
"""同步修改下载任务状态和标签,避免下载器 SDK 阻塞事件循环。"""
download_chain = DownloadChain()
results = []
if tags:
tag_result = download_chain.set_torrents_tag(
hashs=[hash_value], tags=tags, downloader=downloader
)
if tag_result:
results.append(f"成功设置标签:{', '.join(tags)}")
else:
results.append("设置标签失败,请检查任务是否存在或下载器是否可用")
if action:
action_result = download_chain.set_downloading(
hash_str=hash_value, oper=action, name=downloader
)
action_desc = "开始" if action == "start" else "暂停"
if action_result:
results.append(f"成功{action_desc}下载任务")
else:
results.append(f"{action_desc}下载任务失败,请检查任务是否存在或下载器是否可用")
return results
async def run(
self,
hash: str,
action: Optional[str] = None,
tags: Optional[List[str]] = None,
downloader: Optional[str] = None,
**kwargs,
) -> str:
logger.info(
f"执行工具: {self.name}, 参数: hash={hash}, action={action}, tags={tags}, downloader={downloader}"
)
try:
# 校验 hash 格式
if len(hash) != 40 or not all(c in "0123456789abcdefABCDEF" for c in hash):
return "参数错误hash 格式无效,请先使用 query_download_tasks 工具获取正确的 hash。"
# 校验参数:至少需要一个操作
if not action and not tags:
return "参数错误:至少需要指定 actionstart/stop或 tags 中的一个。"
# 校验 action 参数
if action and action not in ("start", "stop"):
return f"参数错误action 只支持 'start'(开始下载)或 'stop'(暂停下载),收到: '{action}'"
results = await self.run_blocking(
"downloader",
self._modify_download_sync,
hash,
action,
tags,
downloader,
)
return f"下载任务 {hash}" + "".join(results)
except Exception as e:
logger.error(f"修改下载任务失败: {e}", exc_info=True)
return f"修改下载任务时发生错误: {str(e)}"