mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-10 15:50:24 +08:00
228 lines
7.1 KiB
Python
228 lines
7.1 KiB
Python
"""装配 Chain 使用的同步网络与相关系统窄端口。"""
|
|
|
|
from collections.abc import Mapping
|
|
from pathlib import Path
|
|
from typing import Any, Optional, Union, cast
|
|
|
|
from app.adapters.network.http import RequestUtils
|
|
from app.adapters.system.host import SystemUtils
|
|
from app.chain.download.ports import (
|
|
DownloadArchivePort,
|
|
DownloadHttpPort,
|
|
DownloadResponsePort,
|
|
configure_download_ports,
|
|
reset_download_ports,
|
|
)
|
|
from app.chain.message import (
|
|
MessageHttpPort,
|
|
MessageResponsePort,
|
|
configure_message_http_port,
|
|
reset_message_http_port,
|
|
)
|
|
from app.chain.scraping import (
|
|
ScrapingHttpPort,
|
|
ScrapingResponsePort,
|
|
ScrapingStreamResponsePort,
|
|
configure_scraping_http_port,
|
|
reset_scraping_http_port,
|
|
)
|
|
from app.chain.system import (
|
|
SystemEnvironmentPort,
|
|
SystemHttpPort,
|
|
SystemResponsePort,
|
|
configure_system_ports,
|
|
reset_system_ports,
|
|
)
|
|
|
|
|
|
class _DownloadHttpAdapter:
|
|
"""把 RequestUtils 收窄为下载链同步 HTTP 端口。"""
|
|
|
|
@staticmethod
|
|
def _request(
|
|
*,
|
|
cookies: Optional[Union[str, dict[str, str]]],
|
|
ua: Optional[str],
|
|
headers: Optional[dict[str, str]],
|
|
proxies: Optional[dict[str, str]],
|
|
timeout: Optional[int],
|
|
) -> RequestUtils:
|
|
"""按下载链传入的代理、认证与超时参数构造一次请求。"""
|
|
options: dict[str, Any] = {
|
|
"cookies": cookies,
|
|
"ua": ua,
|
|
"headers": headers,
|
|
"proxies": proxies,
|
|
"timeout": timeout,
|
|
}
|
|
return RequestUtils(**options)
|
|
|
|
def get(
|
|
self,
|
|
url: str,
|
|
*,
|
|
cookies: Optional[Union[str, dict[str, str]]] = None,
|
|
ua: Optional[str] = None,
|
|
headers: Optional[dict[str, str]] = None,
|
|
proxies: Optional[dict[str, str]] = None,
|
|
timeout: Optional[int] = None,
|
|
params: Optional[dict[str, Any]] = None,
|
|
raise_exception: bool = False,
|
|
) -> Optional[DownloadResponsePort]:
|
|
"""发送下载链 GET 请求并原样保留响应三态。"""
|
|
request = self._request(
|
|
cookies=cookies,
|
|
ua=ua,
|
|
headers=headers,
|
|
proxies=proxies,
|
|
timeout=timeout,
|
|
)
|
|
kwargs: dict[str, Any] = {"raise_exception": raise_exception}
|
|
if params is not None:
|
|
kwargs["params"] = params
|
|
response = request.get_res(url, **kwargs)
|
|
return cast(Optional[DownloadResponsePort], response)
|
|
|
|
def post(
|
|
self,
|
|
url: str,
|
|
*,
|
|
cookies: Optional[Union[str, dict[str, str]]] = None,
|
|
ua: Optional[str] = None,
|
|
headers: Optional[dict[str, str]] = None,
|
|
proxies: Optional[dict[str, str]] = None,
|
|
timeout: Optional[int] = None,
|
|
params: Optional[dict[str, Any]] = None,
|
|
) -> Optional[DownloadResponsePort]:
|
|
"""发送下载链 POST 请求并原样保留响应三态。"""
|
|
request = self._request(
|
|
cookies=cookies,
|
|
ua=ua,
|
|
headers=headers,
|
|
proxies=proxies,
|
|
timeout=timeout,
|
|
)
|
|
kwargs: dict[str, Any] = {}
|
|
if params is not None:
|
|
kwargs["params"] = params
|
|
response = request.post_res(url, **kwargs)
|
|
return cast(Optional[DownloadResponsePort], response)
|
|
|
|
|
|
class _DownloadArchiveAdapter:
|
|
"""把 SystemUtils 收窄为下载链字幕归档端口。"""
|
|
|
|
def unpack(
|
|
self,
|
|
archive_file: Path,
|
|
extract_dir: Path,
|
|
*,
|
|
archive_format: Optional[str],
|
|
) -> None:
|
|
"""使用宿主统一归档实现解压字幕文件。"""
|
|
SystemUtils.unpack_archive(
|
|
archive_file,
|
|
extract_dir,
|
|
archive_format=archive_format,
|
|
)
|
|
|
|
def list_files(self, directory: Path, extensions: tuple[str, ...]) -> list[Path]:
|
|
"""使用宿主统一文件扫描实现列出字幕文件。"""
|
|
return SystemUtils.list_files(directory, list(extensions))
|
|
|
|
|
|
class _MessageHttpAdapter:
|
|
"""把 RequestUtils 收窄为消息附件同步 GET 端口。"""
|
|
|
|
def get(self, url: str, *, timeout: int) -> Optional[MessageResponsePort]:
|
|
"""按消息链固定超时读取附件响应。"""
|
|
response = RequestUtils(timeout=timeout).get_res(url)
|
|
return cast(Optional[MessageResponsePort], response)
|
|
|
|
|
|
class _ScrapingHttpAdapter:
|
|
"""把 RequestUtils 收窄为刮削链普通与流式 GET 端口。"""
|
|
|
|
def get(
|
|
self,
|
|
url: str,
|
|
*,
|
|
proxies: Optional[dict[str, str]],
|
|
ua: str,
|
|
timeout: int,
|
|
) -> Optional[ScrapingResponsePort]:
|
|
"""读取需要完整载荷的音乐封面响应。"""
|
|
options: dict[str, Any] = {
|
|
"proxies": proxies,
|
|
"ua": ua,
|
|
"timeout": timeout,
|
|
}
|
|
response = RequestUtils(**options).get_res(url)
|
|
return cast(Optional[ScrapingResponsePort], response)
|
|
|
|
def stream(
|
|
self,
|
|
url: str,
|
|
*,
|
|
proxies: Optional[dict[str, str]],
|
|
ua: str,
|
|
) -> ScrapingStreamResponsePort:
|
|
"""打开由刮削链上下文关闭的流式图片响应。"""
|
|
options: dict[str, Any] = {"proxies": proxies, "ua": ua}
|
|
response = RequestUtils(**options).get_stream(url=url)
|
|
return cast(ScrapingStreamResponsePort, response)
|
|
|
|
|
|
class _SystemHttpAdapter:
|
|
"""把 RequestUtils 收窄为系统链发布版本 GET 端口。"""
|
|
|
|
def get(
|
|
self,
|
|
url: str,
|
|
*,
|
|
proxies: Optional[dict[str, str]],
|
|
headers: Mapping[str, str],
|
|
) -> Optional[SystemResponsePort]:
|
|
"""按系统配置的代理与 GitHub 请求头读取发布列表。"""
|
|
options: dict[str, Any] = {
|
|
"proxies": proxies,
|
|
"headers": dict(headers),
|
|
}
|
|
response = RequestUtils(**options).get_res(url)
|
|
return cast(Optional[SystemResponsePort], response)
|
|
|
|
|
|
class _SystemEnvironmentAdapter:
|
|
"""把 SystemUtils 收窄为系统链容器环境判断端口。"""
|
|
|
|
def is_docker(self) -> bool:
|
|
"""返回宿主统一环境探针的 Docker 判断。"""
|
|
return bool(SystemUtils.is_docker())
|
|
|
|
|
|
def init_chain_network_ports() -> None:
|
|
"""原子式装配四个 Chain 的六条 Adapter 静态依赖边。"""
|
|
reset_chain_network_ports()
|
|
try:
|
|
configure_download_ports(
|
|
http=cast(DownloadHttpPort, _DownloadHttpAdapter()),
|
|
archive=cast(DownloadArchivePort, _DownloadArchiveAdapter()),
|
|
)
|
|
configure_message_http_port(cast(MessageHttpPort, _MessageHttpAdapter()))
|
|
configure_scraping_http_port(cast(ScrapingHttpPort, _ScrapingHttpAdapter()))
|
|
configure_system_ports(
|
|
http=cast(SystemHttpPort, _SystemHttpAdapter()),
|
|
environment=cast(SystemEnvironmentPort, _SystemEnvironmentAdapter()),
|
|
)
|
|
except Exception:
|
|
reset_chain_network_ports()
|
|
raise
|
|
|
|
|
|
def reset_chain_network_ports() -> None:
|
|
"""清除四个 Chain 的技术端口,支持重复 lifespan 与失败回滚。"""
|
|
reset_system_ports()
|
|
reset_scraping_http_port()
|
|
reset_message_http_port()
|
|
reset_download_ports()
|