"""插件安装统计和评分应用用例。""" from __future__ import annotations from collections.abc import Awaitable, Callable, Mapping, Sequence from typing import Any StatisticLoader = Callable[[], Awaitable[Mapping[str, Any]]] RatingsLoader = Callable[[list[str] | None], Awaitable[Mapping[str, Any]]] RatingLoader = Callable[[str], Awaitable[Mapping[str, Any]]] RatingSubmitter = Callable[[str, float], Awaitable[Mapping[str, Any] | None]] class PluginNotInstalledError(ValueError): """表示评分目标不在当前已安装插件集合中。""" class PluginRatingService: """通过注入的 MoviePilot Server 端口提供插件统计和评分用例。""" def __init__( self, *, installed_plugins: Callable[[], Sequence[str]], statistic: StatisticLoader, ratings: RatingsLoader, rating: RatingLoader, submit: RatingSubmitter, ) -> None: """保存安装状态读取和远程评分窄端口。""" self._installed_plugins = installed_plugins self._statistic = statistic self._ratings = ratings self._rating = rating self._submit = submit async def statistic(self) -> Mapping[str, Any]: """返回插件安装统计。""" return await self._statistic() async def ratings( self, plugin_ids: list[str] | None ) -> Mapping[str, Any]: """批量返回插件评分快照。""" return await self._ratings(plugin_ids) async def rating(self, plugin_id: str) -> Mapping[str, Any]: """返回单个插件评分快照。""" return await self._rating(plugin_id) async def submit(self, plugin_id: str, rating: float) -> Mapping[str, Any] | None: """校验安装状态后提交当前实例评分。""" if plugin_id not in self._installed_plugins(): raise PluginNotInstalledError(f"插件 {plugin_id} 未安装,无法评分") return await self._submit(plugin_id, rating) _rating_service: PluginRatingService | None = None def configure_plugin_rating_service(service: PluginRatingService) -> None: """由启动组合根发布当前 lifespan 的插件评分服务。""" global _rating_service _rating_service = service def get_plugin_rating_service() -> PluginRatingService: """返回已经由启动组合根装配的插件评分服务。""" if _rating_service is None: raise RuntimeError("插件评分服务尚未完成初始化") return _rating_service def reset_plugin_rating_service() -> None: """清除当前 lifespan 的评分服务,供停机和隔离测试使用。""" global _rating_service _rating_service = None