Files
MoviePilot/app/api/dependencies/history.py
jxxghp 6d4ce83837 fix(types): clear host mypy debt and prevent typing regressions
严格检查全部宿主源码,清零类型错误预算并移除按模块类型豁免。
按原因、所属方法、错误码及语法指纹锁定必要兼容例外和站点类型桩,
CI 阻断新增忽略、检查范围退化、本地桩替代真实接口及新的类型错误。

修复空值、异步和供应方类型边界,保持插件与 API 兼容合同,
并补充存储、订阅、通知、Agent 和工作流边界的回归覆盖。
2026-10-21 22:03:18 +08:00

152 lines
4.8 KiB
Python

"""
历史、媒体服务器与 Dashboard 查询依赖。
"""
from typing import cast
from fastapi import Depends
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Session
from app.api.context import get_async_session, get_host_runtime, get_sync_session
from app.application.dashboard import DashboardQueryService
from app.application.history import (
AsyncDownloadHistoryQueryRepository,
DownloadHistoryMutationCommand,
HistoryQueryService,
TransferHistoryLookupService,
TransferHistoryMutationCommand,
)
from app.application.history.mutation import (
DownloadFileMutationRepository,
DownloadHistoryMutationRepository,
HistoryUnitOfWork,
)
from app.application.history.retry import clear_transfer_failures
from app.application.mediaserver import (
AsyncMediaServerQueryRepository,
MediaServerQueryService,
)
from app.application.transfer.execution import TransferExecutionRepository
from app.chain.storage import StorageChain
from app.runtime.events import eventmanager
from app.schemas.file import FileItem as _SchemaFileItem
from app.schemas.types import EventType
from app.startup.composition.context import HostRuntime
def get_mediaserver_query_service(
db: AsyncSession = Depends(get_async_session),
runtime: HostRuntime = Depends(get_host_runtime),
) -> MediaServerQueryService:
"""
组装媒体服务器本地条目异步查询服务。
"""
return MediaServerQueryService(
repository=cast(
AsyncMediaServerQueryRepository,
runtime.history.media_server_repository(db),
)
)
def get_dashboard_query_service(
runtime: HostRuntime = Depends(get_host_runtime),
) -> DashboardQueryService:
"""
组装 Dashboard 媒体与整理历史统计查询服务。
"""
from app.chain.dashboard import DashboardChain
return DashboardQueryService(
repository=runtime.history.transfer_repository,
media_statistics=DashboardChain().media_statistic,
)
def get_download_history_mutation_command(
db: Session = Depends(get_sync_session),
runtime: HostRuntime = Depends(get_host_runtime),
) -> DownloadHistoryMutationCommand:
"""
组装下载历史删除用例及其请求级事务。
"""
return DownloadHistoryMutationCommand(
repository=cast(
DownloadHistoryMutationRepository,
runtime.history.download_repository(db),
),
unit_of_work=cast(
HistoryUnitOfWork, runtime.persistence.sync_transaction(db)
),
)
def get_history_query_service(
db: AsyncSession = Depends(get_async_session),
runtime: HostRuntime = Depends(get_host_runtime),
) -> HistoryQueryService:
"""
组装历史列表和详情异步查询服务。
"""
return HistoryQueryService(
download_repository=cast(
AsyncDownloadHistoryQueryRepository,
runtime.history.download_repository(db),
),
transfer_repository=runtime.history.transfer_repository,
)
def get_transfer_history_lookup_service(
runtime: HostRuntime = Depends(get_host_runtime),
) -> TransferHistoryLookupService:
"""
组装手动整理使用的同步历史投影服务。
"""
return TransferHistoryLookupService(
runtime.history.transfer_repository
)
def get_transfer_execution_repository(
runtime: HostRuntime = Depends(get_host_runtime),
) -> TransferExecutionRepository:
"""
返回 durable 整理任务的显式执行仓储。
"""
return runtime.history.transfer_execution_repository
def get_transfer_history_mutation_command(
db: Session = Depends(get_sync_session),
runtime: HostRuntime = Depends(get_host_runtime),
) -> TransferHistoryMutationCommand:
"""
组装整理历史删除、文件处理和事件发布用例。
"""
storage_chain = StorageChain()
def publish_download_file_deleted(payload: dict[str, object]) -> None:
"""
发送下载文件删除事件;用例不消费事件总线的返回值。
"""
eventmanager.send_event(EventType.DownloadFileDeleted, payload)
return TransferHistoryMutationCommand(
repository=runtime.history.transfer_mutation_repository(db),
download_repository=cast(
DownloadFileMutationRepository,
runtime.history.download_repository(db),
),
transfer_execution_repository=runtime.history.transfer_execution_repository,
unit_of_work=cast(
HistoryUnitOfWork, runtime.persistence.sync_transaction(db)
),
file_item_factory=lambda payload: _SchemaFileItem.model_validate(payload),
file_exists=storage_chain.exists,
delete_media_file=storage_chain.delete_media_file,
publish_download_file_deleted=publish_download_file_deleted,
clear_failures=clear_transfer_failures,
)