mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-04 23:17:20 +08:00
refactor: expand runtime contracts and debt ratchets
This commit is contained in:
@@ -52,6 +52,7 @@ class ChainBase(RecognitionMixin, MessageProcessingMixin, NotificationMixin,
|
||||
self.pluginmanager = context.plugin_manager
|
||||
self.filecache = context.file_cache
|
||||
self.async_filecache = context.async_file_cache
|
||||
self.runtime_config = context.configuration
|
||||
self.data_ports = context.data_ports or get_chain_data_ports()
|
||||
self.durable_event_writer = context.durable_event_writer
|
||||
self._module_dispatcher = context.module_dispatcher_factory(
|
||||
|
||||
+81
-67
@@ -1038,6 +1038,51 @@ class DownloadChain(ChainBase):
|
||||
# 返回 种子文件路径,种子目录名,种子文件清单
|
||||
return content, download_folder, files
|
||||
|
||||
@staticmethod
|
||||
def _apply_resource_download_event(
|
||||
context: Context,
|
||||
episodes: Optional[Set[int]],
|
||||
channel: Optional[NotificationChannel],
|
||||
source: Optional[str],
|
||||
downloader: Optional[str],
|
||||
save_path: Optional[str],
|
||||
userid: Union[str, int, None],
|
||||
username: Optional[str],
|
||||
) -> tuple[Optional[str], Optional[str]]:
|
||||
"""应用资源下载事件覆盖,并校验事件返回的下载目录。"""
|
||||
event_data = ResourceDownloadEventData(
|
||||
context=context,
|
||||
episodes=episodes or context.meta_info.episode_list,
|
||||
channel=channel,
|
||||
origin=source,
|
||||
downloader=downloader,
|
||||
options={
|
||||
"save_path": save_path,
|
||||
"userid": userid,
|
||||
"username": username,
|
||||
"media_category": context.media_info.category,
|
||||
},
|
||||
)
|
||||
event = eventmanager.send_event(ChainEventType.ResourceDownload, event_data)
|
||||
if event and event.event_data:
|
||||
event_data = event.event_data
|
||||
if event_data.cancel:
|
||||
logger.debug(
|
||||
"Resource download canceled by event: %s,Reason: %s",
|
||||
event_data.source,
|
||||
event_data.reason,
|
||||
)
|
||||
return save_path, "下载被事件取消"
|
||||
if event_data.options and "save_path" in event_data.options:
|
||||
save_path = event_data.options.get("save_path")
|
||||
if save_path is None:
|
||||
return None, None
|
||||
try:
|
||||
return validate_download_save_path(save_path), None
|
||||
except ValueError as err:
|
||||
logger.warn(str(err))
|
||||
return save_path, str(err)
|
||||
|
||||
def download_single(self, context: Context,
|
||||
torrent_file: Path = None,
|
||||
torrent_content: Optional[Union[str, bytes]] = None,
|
||||
@@ -1077,40 +1122,12 @@ class DownloadChain(ChainBase):
|
||||
_media = MediaChain().supplement_tmdb_info(_media, _meta)
|
||||
context.media_info = _media
|
||||
|
||||
# 发送资源下载事件,允许外部拦截下载
|
||||
event_data = ResourceDownloadEventData(
|
||||
context=context,
|
||||
episodes=episodes or context.meta_info.episode_list,
|
||||
channel=channel,
|
||||
origin=source,
|
||||
downloader=downloader,
|
||||
options={
|
||||
"save_path": save_path,
|
||||
"userid": userid,
|
||||
"username": username,
|
||||
"media_category": _media.category
|
||||
}
|
||||
save_path, event_error = self._apply_resource_download_event(
|
||||
context, episodes, channel, source, downloader, save_path,
|
||||
userid, username,
|
||||
)
|
||||
# 触发资源下载事件
|
||||
event = eventmanager.send_event(ChainEventType.ResourceDownload, event_data)
|
||||
if event and event.event_data:
|
||||
event_data: ResourceDownloadEventData = event.event_data
|
||||
# 如果事件被取消,跳过资源下载
|
||||
if event_data.cancel:
|
||||
logger.debug(
|
||||
f"Resource download canceled by event: {event_data.source},"
|
||||
f"Reason: {event_data.reason}")
|
||||
return (None, "下载被事件取消") if return_detail else None
|
||||
# 如果事件修改了下载路径,使用新路径
|
||||
if event_data.options and "save_path" in event_data.options:
|
||||
save_path = event_data.options.get("save_path")
|
||||
|
||||
if save_path is not None:
|
||||
try:
|
||||
save_path = validate_download_save_path(save_path)
|
||||
except ValueError as err:
|
||||
logger.warn(str(err))
|
||||
return (None, str(err)) if return_detail else None
|
||||
if event_error:
|
||||
return (None, event_error) if return_detail else None
|
||||
|
||||
# 实际下载的集数
|
||||
download_episodes = episode_rules.format_ranges(list(episodes)) if episodes else None
|
||||
@@ -1913,34 +1930,6 @@ class DownloadChain(ChainBase):
|
||||
logger.error("电视剧缺集检查需要有效的 media_source 和 media_id")
|
||||
return False, no_exists or {}
|
||||
|
||||
def __append_no_exists(_season: int, _episodes: list, _total: int, _start: int):
|
||||
"""
|
||||
添加不存在的季集信息
|
||||
{source:id: [
|
||||
"season": int,
|
||||
"episodes": list,
|
||||
"total_episode": int,
|
||||
"start_episode": int
|
||||
]}
|
||||
"""
|
||||
mediakey = build_media_key(media_source, media_id)
|
||||
if not no_exists.get(mediakey):
|
||||
no_exists[mediakey] = {
|
||||
_season: NotExistMediaInfo(
|
||||
season=_season,
|
||||
episodes=_episodes,
|
||||
total_episode=_total,
|
||||
start_episode=_start
|
||||
)
|
||||
}
|
||||
else:
|
||||
no_exists[mediakey][_season] = NotExistMediaInfo(
|
||||
season=_season,
|
||||
episodes=_episodes,
|
||||
total_episode=_total,
|
||||
start_episode=_start
|
||||
)
|
||||
|
||||
if not no_exists:
|
||||
no_exists = {}
|
||||
|
||||
@@ -2006,8 +1995,10 @@ class DownloadChain(ChainBase):
|
||||
continue
|
||||
# 总集数
|
||||
total_ep = totals.get(season) or len(episodes)
|
||||
__append_no_exists(_season=season, _episodes=[],
|
||||
_total=total_ep, _start=min(episodes))
|
||||
self._append_no_exists(
|
||||
no_exists, media_source, media_id, season, [],
|
||||
total_ep, min(episodes)
|
||||
)
|
||||
return False, no_exists
|
||||
else:
|
||||
# 存在一些,检查每季缺失的季集
|
||||
@@ -2035,12 +2026,16 @@ class DownloadChain(ChainBase):
|
||||
# 全部集存在
|
||||
continue
|
||||
# 添加不存在的季集信息
|
||||
__append_no_exists(_season=season, _episodes=lack_episodes,
|
||||
_total=season_total, _start=min(lack_episodes))
|
||||
self._append_no_exists(
|
||||
no_exists, media_source, media_id, season,
|
||||
lack_episodes, season_total, min(lack_episodes)
|
||||
)
|
||||
else:
|
||||
# 全季不存在
|
||||
__append_no_exists(_season=season, _episodes=[],
|
||||
_total=season_total, _start=min(episodes))
|
||||
self._append_no_exists(
|
||||
no_exists, media_source, media_id, season, [],
|
||||
season_total, min(episodes)
|
||||
)
|
||||
# 存在不完整的剧集
|
||||
if no_exists:
|
||||
logger.debug(f"媒体库中已存在部分剧集,缺失:{no_exists}")
|
||||
@@ -2048,6 +2043,25 @@ class DownloadChain(ChainBase):
|
||||
# 全部存在
|
||||
return True, no_exists
|
||||
|
||||
@staticmethod
|
||||
def _append_no_exists(
|
||||
no_exists: Dict[str, Dict[int, NotExistMediaInfo]],
|
||||
media_source: Optional[MediaSource],
|
||||
media_id: Optional[str],
|
||||
season: int,
|
||||
episodes: list,
|
||||
total: int,
|
||||
start: int,
|
||||
) -> None:
|
||||
"""把一季缺失信息合并到标准媒体身份对应的结果中。"""
|
||||
media_key = build_media_key(media_source, media_id)
|
||||
no_exists.setdefault(media_key, {})[season] = NotExistMediaInfo(
|
||||
season=season,
|
||||
episodes=episodes,
|
||||
total_episode=total,
|
||||
start_episode=start,
|
||||
)
|
||||
|
||||
def remote_downloading(self, channel: NotificationChannel, userid: Union[str, int] = None, source: Optional[str] = None):
|
||||
"""
|
||||
查询正在下载的任务,并发送消息
|
||||
|
||||
@@ -3,7 +3,6 @@ from typing import Any, Optional, List, Dict
|
||||
|
||||
from app.schemas.workflow import FileItem as _SchemaFileItem
|
||||
from app.chain import ChainBase
|
||||
from app.runtime.config import settings
|
||||
from app.application.directory import DirectoryHelper
|
||||
from app.runtime.log import logger
|
||||
|
||||
@@ -148,7 +147,7 @@ class StorageChain(ChainBase):
|
||||
"""
|
||||
删除媒体文件,以及不含媒体文件的目录
|
||||
"""
|
||||
media_exts = settings.RMT_MEDIAEXT + settings.DOWNLOAD_TMPEXT + settings.RMT_SUBEXT + settings.RMT_AUDIOEXT
|
||||
media_exts = self.runtime_config.media_extensions
|
||||
fileitem_path = Path(fileitem.path) if fileitem.path else Path("")
|
||||
if len(fileitem_path.parts) <= 2:
|
||||
logger.warn(f"【{fileitem.storage}】{fileitem.path} 根目录或一级目录不允许删除")
|
||||
|
||||
Reference in New Issue
Block a user