mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-05-13 07:26:45 +00:00
Route title and path lookups through the fallback-aware entrypoints so auxiliary matches can reuse pre-assist keywords without forcing image fetches in lightweight flows. Also reduce noisy agent shutdown logging during cleanup.
120 lines
4.7 KiB
Python
120 lines
4.7 KiB
Python
from typing import Optional
|
|
|
|
from pydantic import Field
|
|
|
|
from app.workflow.actions import BaseAction
|
|
from app.chain.download import DownloadChain
|
|
from app.chain.media import MediaChain
|
|
from app.core.config import global_vars
|
|
from app.core.metainfo import MetaInfo
|
|
from app.log import logger
|
|
from app.schemas import ActionParams, ActionContext, DownloadTask, MediaType
|
|
|
|
|
|
class AddDownloadParams(ActionParams):
|
|
"""
|
|
添加下载资源参数
|
|
"""
|
|
downloader: Optional[str] = Field(default=None, description="下载器")
|
|
save_path: Optional[str] = Field(default=None, description="保存路径, 支持<storage>:<path>, 如rclone:/MP, smb:/server/share/Movies等")
|
|
labels: Optional[str] = Field(default=None, description="标签(,分隔)")
|
|
only_lack: Optional[bool] = Field(default=False, description="仅下载缺失的资源")
|
|
|
|
|
|
class AddDownloadAction(BaseAction):
|
|
"""
|
|
添加下载资源
|
|
"""
|
|
|
|
def __init__(self, action_id: str):
|
|
super().__init__(action_id)
|
|
self._added_downloads = []
|
|
self._has_error = False
|
|
|
|
@classmethod
|
|
@property
|
|
def name(cls) -> str: # noqa
|
|
return "添加下载"
|
|
|
|
@classmethod
|
|
@property
|
|
def description(cls) -> str: # noqa
|
|
return "根据资源列表添加下载任务"
|
|
|
|
@classmethod
|
|
@property
|
|
def data(cls) -> dict: # noqa
|
|
return AddDownloadParams().model_dump()
|
|
|
|
@property
|
|
def success(self) -> bool:
|
|
return not self._has_error
|
|
|
|
def execute(self, workflow_id: int, params: dict, context: ActionContext) -> ActionContext:
|
|
"""
|
|
将上下文中的torrents添加到下载任务中
|
|
"""
|
|
params = AddDownloadParams(**params)
|
|
_started = False
|
|
for t in context.torrents:
|
|
if global_vars.is_workflow_stopped(workflow_id):
|
|
break
|
|
# 检查缓存
|
|
cache_key = f"{t.torrent_info.site}-{t.torrent_info.title}"
|
|
if self.check_cache(workflow_id, cache_key):
|
|
logger.info(f"{t.torrent_info.title} 已添加过下载,跳过")
|
|
continue
|
|
if not t.meta_info:
|
|
t.meta_info = MetaInfo(title=t.torrent_info.title, subtitle=t.torrent_info.description)
|
|
if not t.media_info:
|
|
t.media_info = MediaChain().recognize_by_meta(
|
|
t.meta_info,
|
|
obtain_images=False,
|
|
)
|
|
if not t.media_info:
|
|
self._has_error = True
|
|
logger.warning(f"{t.torrent_info.title} 未识别到媒体信息,无法下载")
|
|
continue
|
|
if params.only_lack:
|
|
exists_info = DownloadChain().media_exists(t.media_info)
|
|
if exists_info:
|
|
if t.media_info.type == MediaType.MOVIE:
|
|
# 电影
|
|
logger.warning(f"{t.torrent_info.title} 媒体库中已存在,跳过")
|
|
continue
|
|
else:
|
|
# 电视剧
|
|
exists_seasons = exists_info.seasons or {}
|
|
if len(t.meta_info.season_list) > 1:
|
|
# 多季不下载
|
|
logger.warning(f"{t.meta_info.title} 有多季,跳过")
|
|
continue
|
|
else:
|
|
exists_episodes = exists_seasons.get(t.meta_info.begin_season)
|
|
if exists_episodes:
|
|
if set(t.meta_info.episode_list).issubset(exists_episodes):
|
|
logger.warning(
|
|
f"{t.meta_info.title} 第 {t.meta_info.begin_season} 季第 {t.meta_info.episode_list} 集已存在,跳过")
|
|
continue
|
|
|
|
_started = True
|
|
did = DownloadChain().download_single(context=t,
|
|
downloader=params.downloader,
|
|
save_path=params.save_path,
|
|
label=params.labels)
|
|
if did:
|
|
self._added_downloads.append(did)
|
|
# 保存缓存
|
|
self.save_cache(workflow_id, cache_key)
|
|
|
|
if self._added_downloads:
|
|
logger.info(f"已添加 {len(self._added_downloads)} 个下载任务")
|
|
context.downloads.extend(
|
|
[DownloadTask(download_id=did, downloader=params.downloader) for did in self._added_downloads]
|
|
)
|
|
elif _started:
|
|
self._has_error = True
|
|
|
|
self.job_done(f"已添加 {len(self._added_downloads)} 个下载任务")
|
|
return context
|