mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-03 22:04:57 +08:00
refactor(architecture): keep subscription owners within ratchet
This commit is contained in:
@@ -22,6 +22,29 @@ from app.schemas.types import MUSIC_ENTITY_ALBUM, MediaType, NotificationChannel
|
||||
subscribe_interaction_manager = SlashInteractionManager()
|
||||
|
||||
|
||||
def _format_subscribe_progress(subscribe: SubscriptionSnapshot) -> str:
|
||||
"""构造订阅的季和进度说明,专辑按累计曲目数展示。"""
|
||||
if subscribe.type == MediaType.MOVIE.value:
|
||||
return "电影"
|
||||
if (
|
||||
subscribe.type == MediaType.MUSIC.value
|
||||
and subscribe.music_type == MUSIC_ENTITY_ALBUM
|
||||
and subscribe.total_tracks
|
||||
):
|
||||
completed_tracks = compute_subscribe_completed_tracks(subscribe) or 0
|
||||
return f"专辑 [{completed_tracks}/{subscribe.total_tracks}]"
|
||||
season = subscribe.season if subscribe.season is not None else 1
|
||||
if subscribe.total_episode:
|
||||
lack_episode = (
|
||||
subscribe.lack_episode
|
||||
if subscribe.lack_episode is not None
|
||||
else subscribe.total_episode
|
||||
)
|
||||
downloaded = max(subscribe.total_episode - lack_episode, 0)
|
||||
return f"第{season}季 [{downloaded}/{subscribe.total_episode}]"
|
||||
return f"第{season}季"
|
||||
|
||||
|
||||
class SubscribeInteractionActions(Protocol):
|
||||
"""
|
||||
声明订阅交互需要调用的业务动作。
|
||||
@@ -540,28 +563,8 @@ class SubscribeInteractionHandler:
|
||||
|
||||
@staticmethod
|
||||
def _format_subscribe_progress(subscribe: SubscriptionSnapshot) -> str:
|
||||
"""
|
||||
构造订阅的季和进度说明。
|
||||
"""
|
||||
if subscribe.type == MediaType.MOVIE.value:
|
||||
return "电影"
|
||||
if (
|
||||
subscribe.type == MediaType.MUSIC.value
|
||||
and subscribe.music_type == MUSIC_ENTITY_ALBUM
|
||||
and subscribe.total_tracks
|
||||
):
|
||||
completed_tracks = compute_subscribe_completed_tracks(subscribe) or 0
|
||||
return f"专辑 [{completed_tracks}/{subscribe.total_tracks}]"
|
||||
season = subscribe.season if subscribe.season is not None else 1
|
||||
if subscribe.total_episode:
|
||||
lack_episode = (
|
||||
subscribe.lack_episode
|
||||
if subscribe.lack_episode is not None
|
||||
else subscribe.total_episode
|
||||
)
|
||||
downloaded = max(subscribe.total_episode - lack_episode, 0)
|
||||
return f"第{season}季 [{downloaded}/{subscribe.total_episode}]"
|
||||
return f"第{season}季"
|
||||
"""构造订阅的季和进度说明。"""
|
||||
return _format_subscribe_progress(subscribe)
|
||||
|
||||
@staticmethod
|
||||
def _subscribe_prompt(awaiting_input: Optional[str]) -> str:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from collections.abc import Mapping
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
||||
|
||||
from app.application.classification.reference import effective_classification_snapshot
|
||||
from app.application.subscription.contract import (
|
||||
@@ -129,10 +129,9 @@ class SubscribeCompletionOwner(_SubscribeOwnerBase):
|
||||
)
|
||||
subscribe = facts["subscribe"]
|
||||
elif downloads and meta.type == MediaType.MUSIC:
|
||||
subscribe = self._SubscribeChain__record_music_download_facts(
|
||||
subscribe=subscribe,
|
||||
downloads=downloads,
|
||||
)
|
||||
apply_update = self._SubscribeChain__apply_subscribe_update
|
||||
update_note = self._SubscribeChain__update_subscribe_note
|
||||
subscribe = _record_music_download_facts(apply_update, update_note, subscribe, downloads)
|
||||
elif downloads:
|
||||
subscribe = self._SubscribeChain__update_subscribe_note(
|
||||
subscribe=subscribe,
|
||||
@@ -252,54 +251,6 @@ class SubscribeCompletionOwner(_SubscribeOwnerBase):
|
||||
return updated or subscribe
|
||||
return subscribe
|
||||
|
||||
def _SubscribeChain__record_music_download_facts(
|
||||
self,
|
||||
subscribe: SubscriptionSnapshot,
|
||||
downloads: Optional[List[Context]],
|
||||
) -> SubscriptionSnapshot:
|
||||
"""合并本轮专辑音轨事实,按统一媒体身份去重后返回最新订阅快照。"""
|
||||
if not downloads:
|
||||
return subscribe
|
||||
if getattr(subscribe, "music_type", None) != MUSIC_ENTITY_ALBUM:
|
||||
return self._SubscribeChain__update_subscribe_note(
|
||||
subscribe=subscribe,
|
||||
downloads=downloads,
|
||||
)
|
||||
|
||||
downloaded_tracks = {
|
||||
item
|
||||
for item in (getattr(subscribe, "downloaded_tracks", None) or [])
|
||||
if isinstance(item, str) and item
|
||||
}
|
||||
subscribe_identity = resolve_media_identity(media=subscribe)
|
||||
for context in downloads:
|
||||
media = context.media_info
|
||||
if not media or media.type != MediaType.MUSIC:
|
||||
continue
|
||||
if subscribe_identity != resolve_media_identity(media=media):
|
||||
continue
|
||||
downloaded_tracks.update(
|
||||
item
|
||||
for item in (getattr(context, "music_track_keys", None) or [])
|
||||
if isinstance(item, str) and item
|
||||
)
|
||||
if not downloaded_tracks:
|
||||
return subscribe
|
||||
|
||||
updated = self._SubscribeChain__apply_subscribe_update(
|
||||
subscribe,
|
||||
{
|
||||
"downloaded_tracks": sorted(downloaded_tracks),
|
||||
"last_update": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
},
|
||||
scene="music_download_tracks",
|
||||
)
|
||||
logger.info(
|
||||
f"订阅 {subscribe.name} 记录已下载专辑曲目:"
|
||||
f"{len(downloaded_tracks)}/{subscribe.total_tracks or 0}"
|
||||
)
|
||||
return updated or subscribe
|
||||
|
||||
@staticmethod
|
||||
def _SubscribeChain__get_downloaded(subscribe: SubscriptionSnapshot) -> List[int]:
|
||||
"""
|
||||
@@ -577,3 +528,50 @@ class SubscribeCompletionOwner(_SubscribeOwnerBase):
|
||||
)
|
||||
logger.info(f"订阅 {subscribe_name} 缺失剧集数更新为:{no_exists}")
|
||||
return False, no_exists
|
||||
|
||||
|
||||
def _record_music_download_facts(
|
||||
apply_update: Callable[..., SubscriptionSnapshot],
|
||||
update_note: Callable[..., SubscriptionSnapshot],
|
||||
subscribe: SubscriptionSnapshot,
|
||||
downloads: Optional[List[Context]],
|
||||
) -> SubscriptionSnapshot:
|
||||
"""合并本轮专辑音轨事实,按统一媒体身份去重后返回最新订阅快照。"""
|
||||
if not downloads:
|
||||
return subscribe
|
||||
if getattr(subscribe, "music_type", None) != MUSIC_ENTITY_ALBUM:
|
||||
return update_note(subscribe=subscribe, downloads=downloads)
|
||||
|
||||
downloaded_tracks = {
|
||||
item
|
||||
for item in (getattr(subscribe, "downloaded_tracks", None) or [])
|
||||
if isinstance(item, str) and item
|
||||
}
|
||||
subscribe_identity = resolve_media_identity(media=subscribe)
|
||||
for context in downloads:
|
||||
media = context.media_info
|
||||
if not media or media.type != MediaType.MUSIC:
|
||||
continue
|
||||
if subscribe_identity != resolve_media_identity(media=media):
|
||||
continue
|
||||
downloaded_tracks.update(
|
||||
item
|
||||
for item in (getattr(context, "music_track_keys", None) or [])
|
||||
if isinstance(item, str) and item
|
||||
)
|
||||
if not downloaded_tracks:
|
||||
return subscribe
|
||||
|
||||
updated = apply_update(
|
||||
subscribe,
|
||||
{
|
||||
"downloaded_tracks": sorted(downloaded_tracks),
|
||||
"last_update": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
},
|
||||
scene="music_download_tracks",
|
||||
)
|
||||
logger.info(
|
||||
f"订阅 {subscribe.name} 记录已下载专辑曲目:"
|
||||
f"{len(downloaded_tracks)}/{subscribe.total_tracks or 0}"
|
||||
)
|
||||
return updated or subscribe
|
||||
|
||||
@@ -38,6 +38,14 @@ from app.schemas.types import (
|
||||
)
|
||||
|
||||
|
||||
def _public_subscribe_view(subscribe: SubscriptionSnapshot) -> _SchemaSubscribe:
|
||||
"""将订阅内部快照投影为公开 DTO,并隐藏活动音轨事实。"""
|
||||
payload = subscribe.to_dict()
|
||||
payload["completed_tracks"] = compute_subscribe_completed_tracks(subscribe)
|
||||
payload.pop("downloaded_tracks", None)
|
||||
return _SchemaSubscribe(**payload)
|
||||
|
||||
|
||||
class SubscribeQueryOwner(_SubscribeOwnerBase):
|
||||
"""订阅查询、关注与现存媒体投影,作为 SubscribeChain 的单一职责实现 owner。"""
|
||||
|
||||
@@ -401,10 +409,7 @@ class SubscribeQueryOwner(_SubscribeOwnerBase):
|
||||
self._append_subscribe_media_servers(subscribe, mediainfo, episodes)
|
||||
|
||||
# 更新订阅信息
|
||||
subscribe_payload = subscribe.to_dict()
|
||||
subscribe_payload["completed_tracks"] = compute_subscribe_completed_tracks(subscribe)
|
||||
subscribe_payload.pop("downloaded_tracks", None)
|
||||
subscribe_info.subscribe = _SchemaSubscribe(**subscribe_payload)
|
||||
subscribe_info.subscribe = _public_subscribe_view(subscribe)
|
||||
subscribe_info.episodes = episodes
|
||||
return subscribe_info
|
||||
|
||||
|
||||
Reference in New Issue
Block a user