Files
MoviePilot/app/application/dashboard.py
jxxghp 721c03734a feat(widget): 提供受限凭据和只读快照接口 (#7175)
* feat(widget): add restricted read-only snapshot foundation

* test(widget): 补齐运行时与文档迁移契约
2026-10-25 06:02:47 +08:00

104 lines
3.5 KiB
Python

"""
Dashboard 统计查询用例。
"""
from collections.abc import Callable
from typing import Optional, Protocol
from app.application.history import (
TransferHistoryMonthlyStatistics,
TransferHistoryStatisticSnapshot,
)
from app.schemas.dashboard import Statistic
class TransferHistoryQueryRepository(Protocol):
"""
Dashboard 所需的整理历史统计端口。
"""
def monthly_media_statistics(self) -> TransferHistoryMonthlyStatistics:
"""
返回本月电影、剧集、单集和音乐数量。
:return: 本月按媒体类型与剧集维度汇总的新增数量
"""
...
async def async_statistic(
self,
days: int = 7,
) -> list[TransferHistoryStatisticSnapshot]:
"""
返回最近若干天的整理趋势。
:param days: 查询最近的自然日数量,默认 7 天
:return: 按日期汇总的整理数量与大小等趋势记录
"""
...
class DashboardQueryService:
"""
汇总媒体服务数据与整理历史统计。
"""
def __init__(
self,
*,
repository: TransferHistoryQueryRepository,
media_statistics: Callable[[Optional[str]], Optional[list[Statistic]]],
) -> None:
"""
保存整理历史端口和媒体服务统计提供方。
"""
self._repository = repository
self._media_statistics = media_statistics
def statistic(self, name: Optional[str] = None, *, require_source: bool = False) -> Statistic:
"""
返回媒体服务总量和本月新增量。
:param name: 指定媒体服务;为空时汇总全部已配置服务
:param require_source: 缺少成功来源时拒绝把失败作为成功的零,网页默认保持旧行为
:return: 当前来源计数与本月新增统计
:raises ValueError: 严格读取没有成功来源
"""
media_statistics = self._media_statistics(name)
if require_source and not media_statistics:
raise ValueError("媒体统计来源暂不可用")
if media_statistics:
movie_count = tv_count = music_count = user_count = episode_count = 0
has_episode_count = False
for item in media_statistics:
movie_count += item.movie_count or 0
tv_count += item.tv_count or 0
music_count += item.music_count or 0
user_count += item.user_count or 0
if item.episode_count is not None:
episode_count += item.episode_count or 0
has_episode_count = True
result = Statistic(
movie_count=movie_count,
tv_count=tv_count,
music_count=music_count,
user_count=user_count,
episode_count=episode_count if has_episode_count else None,
)
else:
result = Statistic()
monthly = self._repository.monthly_media_statistics()
result.movie_count_month = monthly.movies
result.tv_count_month = monthly.tv_shows
result.episode_count_month = monthly.episodes
result.music_count_month = monthly.music
return result
async def transfer(self, days: int = 7) -> list[int]:
"""
返回最近若干天的整理数量序列。
"""
rows = await self._repository.async_statistic(days)
return [row.count for row in rows]