diff --git a/app/chain/media/projection.py b/app/chain/media/projection.py index 0f86f2166..e15db01ec 100644 --- a/app/chain/media/projection.py +++ b/app/chain/media/projection.py @@ -9,7 +9,6 @@ from typing import Any, Final, Optional, cast from app.chain.media.contract import _MediaOwnerBase from app.domain.metainfo import MetaInfo -from app.domain.projection.bangumi import resolve_media_type as resolve_bangumi_media_type from app.schemas.event import ( MediaRecognizeConvertEventData as _SchemaMediaRecognizeConvertEventData, ) @@ -163,6 +162,8 @@ def _build_bangumi_tmdb_match( source_info: _ProjectionSource, ) -> Optional[_TmdbMatch]: """把 Bangumi 详情投影为 TMDB 名称匹配请求。""" + from app.domain.projection.bangumi import resolve_media_type + title = _optional_text(source_info.get("name")) if not title: return None @@ -173,7 +174,7 @@ def _build_bangumi_tmdb_match( return _TmdbMatch( names=_unique_names((localized_meta.name, meta.name)), year=MediaProjectionOwner._extract_year_from_bangumi(source_info), - media_type=plan.media_type or resolve_bangumi_media_type(source_info), + media_type=plan.media_type or resolve_media_type(source_info), season=selected_season, ) @@ -205,6 +206,8 @@ def _build_bangumi_douban_match( source_info: _ProjectionSource, ) -> Optional[_DoubanMatch]: """把 Bangumi 详情投影为豆瓣名称、年份、类型和季请求。""" + from app.domain.projection.bangumi import resolve_media_type + title = _optional_text(source_info.get("name_cn") or source_info.get("name")) if not title: return None @@ -213,7 +216,7 @@ def _build_bangumi_douban_match( return _DoubanMatch( name=meta.name, year=MediaProjectionOwner._extract_year_from_bangumi(source_info), - media_type=plan.media_type or resolve_bangumi_media_type(source_info), + media_type=plan.media_type or resolve_media_type(source_info), season=selected_season, ) diff --git a/app/domain/context.py b/app/domain/context.py index dbe75f025..8fcce4850 100644 --- a/app/domain/context.py +++ b/app/domain/context.py @@ -18,15 +18,6 @@ from app.domain.meta.metamusic import ( normalize_audio_format, ) from app.domain.metainfo import MetaInfo -from app.domain.projection.anilist import format_date as _format_anilist_date -from app.domain.projection.anilist import project as _project_anilist -from app.domain.projection.anilist import resolve_media_type as _resolve_anilist_media_type -from app.domain.projection.anilist import select_chinese_title as _select_anilist_chinese_title -from app.domain.projection.bangumi import project as _project_bangumi -from app.domain.projection.bangumi import resolve_media_type as _resolve_bangumi_media_type -from app.domain.projection.douban import project as _project_douban -from app.domain.projection.tmdb import configure_image_url_builder as _configure_tmdb_image_url_builder -from app.domain.projection.tmdb import project as _project_tmdb from app.foundation import temporal as time_tools from app.schemas.media import normalize_media_source, resolve_media_identity from app.schemas.types import ( @@ -66,7 +57,37 @@ def configure_tmdb_image_url_builder( builder: Callable[[str], Optional[str]], ) -> None: """兼容旧入口,将 TMDB 图片地址构造器交给来源投影 owner。""" - _configure_tmdb_image_url_builder(builder) + from app.domain.projection.tmdb import configure_image_url_builder + + configure_image_url_builder(builder) + + +def _project_tmdb(state: dict, info: dict) -> dict: + """按需加载 TMDB 投影 owner,避免领域上下文冷导入全部来源实现。""" + from app.domain.projection.tmdb import project + + return project(state, info) + + +def _project_douban(state: dict, info: dict) -> dict: + """按需加载豆瓣投影 owner,避免领域上下文冷导入全部来源实现。""" + from app.domain.projection.douban import project + + return project(state, info) + + +def _project_bangumi(state: dict, info: dict) -> dict: + """按需加载 Bangumi 投影 owner,避免领域上下文冷导入全部来源实现。""" + from app.domain.projection.bangumi import project + + return project(state, info) + + +def _project_anilist(state: dict, info: dict) -> dict: + """按需加载 AniList 投影 owner,避免领域上下文冷导入全部来源实现。""" + from app.domain.projection.anilist import project + + return project(state, info) def _validate_music_type(value: object) -> None: @@ -1356,7 +1377,9 @@ class MediaInfo: @staticmethod def get_bangumi_media_type(info: dict) -> MediaType: """兼容旧方法,委托 Bangumi 来源 owner 解析媒体类型。""" - return _resolve_bangumi_media_type(info) + from app.domain.projection.bangumi import resolve_media_type + + return resolve_media_type(info) def set_bangumi_info(self, info: dict) -> None: """通过 Bangumi 来源 owner 初始化统一媒体字段。""" @@ -1365,17 +1388,23 @@ class MediaInfo: @staticmethod def get_anilist_media_type(info: dict) -> MediaType: """兼容旧方法,委托 AniList 来源 owner 解析媒体类型。""" - return _resolve_anilist_media_type(info) + from app.domain.projection.anilist import resolve_media_type + + return resolve_media_type(info) @staticmethod def _anilist_date(date_info: dict) -> Optional[str]: """兼容旧私有补丁点,委托 AniList owner 格式化模糊日期。""" - return _format_anilist_date(date_info) + from app.domain.projection.anilist import format_date + + return format_date(date_info) @staticmethod def _anilist_chinese_title(info: dict) -> Optional[str]: """兼容旧私有补丁点,委托 AniList owner 选择中文标题。""" - return _select_anilist_chinese_title(info) + from app.domain.projection.anilist import select_chinese_title + + return select_chinese_title(info) def set_anilist_info(self, info: dict) -> None: """通过 AniList 来源 owner 初始化统一媒体字段。""" diff --git a/app/startup/initializers/domain.py b/app/startup/initializers/domain.py index b72999f3a..0dfcc53e5 100644 --- a/app/startup/initializers/domain.py +++ b/app/startup/initializers/domain.py @@ -12,14 +12,13 @@ from app.domain.meta.releasegroup import configure_release_groups_provider from app.domain.meta.runtime import configure_recognition_runtime from app.domain.meta.words import configure_custom_words_provider from app.domain.metainfo import clear_rust_parse_options_cache -from app.domain.projection.tmdb import ( - configure_image_url_builder as configure_tmdb_image_url_builder, -) from app.runtime.settings import get_runtime_setting def configure_domain_dependencies() -> None: """在组合根集中注入领域模型需要的配置、持久化规则和加速适配器。""" + from app.domain.projection.tmdb import configure_image_url_builder + rule_service = RecognitionRuleService() configure_dns_resolver(SocketDnsResolver()) configure_disk_topology(SystemUtils) @@ -29,7 +28,7 @@ def configure_domain_dependencies() -> None: configure_release_groups_provider(rule_service.get_release_groups) configure_custom_words_provider(rule_service.get_custom_words) configure_search_source_provider(lambda: get_runtime_setting('SEARCH_SOURCE')) - configure_tmdb_image_url_builder(get_runtime_setting('TMDB_IMAGE_URL')) + configure_image_url_builder(get_runtime_setting('TMDB_IMAGE_URL')) configure_recognition_runtime( media_extensions_provider=lambda: ( *get_runtime_setting('RMT_MEDIAEXT'),