mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-05-08 14:23:27 +08:00
205 lines
8.1 KiB
Python
205 lines
8.1 KiB
Python
"""添加订阅工具"""
|
|
|
|
from typing import Optional, Type, List
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
from app.agent.tools.base import MoviePilotTool
|
|
from app.chain.subscribe import SubscribeChain
|
|
from app.log import logger
|
|
from app.schemas.types import MediaType
|
|
|
|
|
|
class AddSubscribeInput(BaseModel):
|
|
"""添加订阅工具的输入参数模型"""
|
|
|
|
explanation: str = Field(
|
|
...,
|
|
description="Clear explanation of why this tool is being used in the current context",
|
|
)
|
|
title: str = Field(
|
|
...,
|
|
description="The title of the media to subscribe to (e.g., 'The Matrix', 'Breaking Bad')",
|
|
)
|
|
year: str = Field(
|
|
...,
|
|
description="Release year of the media (required for accurate identification)",
|
|
)
|
|
media_type: str = Field(..., description="Allowed values: movie, tv")
|
|
season: Optional[int] = Field(
|
|
None,
|
|
description=(
|
|
"Season number for TV shows (optional). If omitted, the subscription defaults to season 1 only. "
|
|
"To subscribe multiple seasons or the full series, call this tool separately for each season."
|
|
),
|
|
)
|
|
tmdb_id: Optional[int] = Field(
|
|
None,
|
|
description="TMDB database ID for precise media identification (optional, can be obtained from search_media tool)",
|
|
)
|
|
douban_id: Optional[str] = Field(
|
|
None,
|
|
description="Douban ID for precise media identification (optional, alternative to tmdb_id)",
|
|
)
|
|
start_episode: Optional[int] = Field(
|
|
None,
|
|
description="Starting episode number for TV shows (optional, defaults to 1 if not specified)",
|
|
)
|
|
total_episode: Optional[int] = Field(
|
|
None,
|
|
description="Total number of episodes for TV shows (optional, will be auto-detected from TMDB if not specified)",
|
|
)
|
|
quality: Optional[str] = Field(
|
|
None,
|
|
description="Quality filter as regular expression (optional, e.g., 'BluRay|WEB-DL|HDTV')",
|
|
)
|
|
resolution: Optional[str] = Field(
|
|
None,
|
|
description="Resolution filter as regular expression (optional, e.g., '1080p|720p|2160p')",
|
|
)
|
|
effect: Optional[str] = Field(
|
|
None,
|
|
description="Effect filter as regular expression (optional, e.g., 'HDR|DV|SDR')",
|
|
)
|
|
filter_groups: Optional[List[str]] = Field(
|
|
None,
|
|
description="List of filter rule group names to apply (optional, can be obtained from query_rule_groups tool)",
|
|
)
|
|
sites: Optional[List[int]] = Field(
|
|
None,
|
|
description="List of site IDs to search from (optional, can be obtained from query_sites tool)",
|
|
)
|
|
|
|
|
|
class AddSubscribeTool(MoviePilotTool):
|
|
name: str = "add_subscribe"
|
|
description: str = (
|
|
"Add media subscription to create automated download rules for movies and TV shows. "
|
|
"The system will automatically search and download new episodes or releases based on the subscription criteria. "
|
|
"For TV shows, omitting `season` subscribes season 1 only by default; to subscribe multiple seasons or "
|
|
"the full series, call this tool once per season. Supports advanced filtering options like quality, "
|
|
"resolution, and effect filters using regular expressions."
|
|
)
|
|
args_schema: Type[BaseModel] = AddSubscribeInput
|
|
|
|
def get_tool_message(self, **kwargs) -> Optional[str]:
|
|
"""根据订阅参数生成友好的提示消息"""
|
|
title = kwargs.get("title", "")
|
|
year = kwargs.get("year", "")
|
|
media_type = kwargs.get("media_type", "")
|
|
season = kwargs.get("season")
|
|
|
|
message = f"添加订阅: {title}"
|
|
if year:
|
|
message += f" ({year})"
|
|
if media_type:
|
|
message += f" [{media_type}]"
|
|
if season:
|
|
message += f" 第{season}季"
|
|
elif media_type == "tv":
|
|
message += " 第1季(默认)"
|
|
|
|
return message
|
|
|
|
async def run(
|
|
self,
|
|
title: str,
|
|
year: str,
|
|
media_type: str,
|
|
season: Optional[int] = None,
|
|
tmdb_id: Optional[int] = None,
|
|
douban_id: Optional[str] = None,
|
|
start_episode: Optional[int] = None,
|
|
total_episode: Optional[int] = None,
|
|
quality: Optional[str] = None,
|
|
resolution: Optional[str] = None,
|
|
effect: Optional[str] = None,
|
|
filter_groups: Optional[List[str]] = None,
|
|
sites: Optional[List[int]] = None,
|
|
**kwargs,
|
|
) -> str:
|
|
logger.info(
|
|
f"执行工具: {self.name}, 参数: title={title}, year={year}, media_type={media_type}, "
|
|
f"season={season}, tmdb_id={tmdb_id}, douban_id={douban_id}, start_episode={start_episode}, "
|
|
f"total_episode={total_episode}, quality={quality}, resolution={resolution}, "
|
|
f"effect={effect}, filter_groups={filter_groups}, sites={sites}"
|
|
)
|
|
|
|
try:
|
|
subscribe_chain = SubscribeChain()
|
|
media_type_enum = MediaType.from_agent(media_type)
|
|
if not media_type_enum:
|
|
return f"错误:无效的媒体类型 '{media_type}',支持的类型:'movie', 'tv'"
|
|
effective_season = (
|
|
season
|
|
if season is not None
|
|
else 1
|
|
if media_type_enum == MediaType.TV
|
|
else None
|
|
)
|
|
|
|
# 构建额外的订阅参数
|
|
subscribe_kwargs = {}
|
|
if start_episode is not None:
|
|
subscribe_kwargs["start_episode"] = start_episode
|
|
if total_episode is not None:
|
|
subscribe_kwargs["total_episode"] = total_episode
|
|
if quality:
|
|
subscribe_kwargs["quality"] = quality
|
|
if resolution:
|
|
subscribe_kwargs["resolution"] = resolution
|
|
if effect:
|
|
subscribe_kwargs["effect"] = effect
|
|
if filter_groups:
|
|
subscribe_kwargs["filter_groups"] = filter_groups
|
|
if sites:
|
|
subscribe_kwargs["sites"] = sites
|
|
|
|
sid, message = await subscribe_chain.async_add(
|
|
mtype=media_type_enum,
|
|
title=title,
|
|
year=year,
|
|
tmdbid=tmdb_id,
|
|
doubanid=douban_id,
|
|
season=season,
|
|
username=self._user_id,
|
|
**subscribe_kwargs,
|
|
)
|
|
if sid:
|
|
if message and "已存在" in message:
|
|
result_msg = f"订阅已存在:{title} ({year})"
|
|
if effective_season is not None:
|
|
result_msg += f" 第{effective_season}季"
|
|
result_msg += "。如需修改参数请先删除旧订阅。"
|
|
return result_msg
|
|
|
|
result_msg = f"成功添加订阅:{title} ({year})"
|
|
if effective_season is not None:
|
|
result_msg += f" 第{effective_season}季"
|
|
if season is None:
|
|
result_msg += "(未指定季号,默认按第一季订阅)"
|
|
if subscribe_kwargs:
|
|
params = []
|
|
if start_episode is not None:
|
|
params.append(f"开始集数: {start_episode}")
|
|
if total_episode is not None:
|
|
params.append(f"总集数: {total_episode}")
|
|
if quality:
|
|
params.append(f"质量过滤: {quality}")
|
|
if resolution:
|
|
params.append(f"分辨率过滤: {resolution}")
|
|
if effect:
|
|
params.append(f"特效过滤: {effect}")
|
|
if filter_groups:
|
|
params.append(f"规则组: {', '.join(filter_groups)}")
|
|
if sites:
|
|
params.append(f"站点: {', '.join(map(str, sites))}")
|
|
if params:
|
|
result_msg += f"\n配置参数: {', '.join(params)}"
|
|
return result_msg
|
|
else:
|
|
return f"添加订阅失败:{message}"
|
|
except Exception as e:
|
|
logger.error(f"添加订阅失败: {e}", exc_info=True)
|
|
return f"添加订阅时发生错误: {str(e)}"
|