mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-29 12:06:51 +08:00
refactor: type recognition module contracts
This commit is contained in:
@@ -79,6 +79,9 @@ _METHOD_CONTRACTS = {
|
||||
result_contract="MediaInfo | None", aggregation=ModuleResultAggregation.FIRST_NON_EMPTY,
|
||||
required_parameters=("meta", "mtype", "media_source", "media_id", "episode_group", "cache"),
|
||||
),
|
||||
"match_doubaninfo": ModuleMethodContract(family="media-recognition", input_contract="DoubanMatchRequest", result_contract="dict[str, Any] | None", result_shape=ModuleResultShape.MAPPING, aggregation=ModuleResultAggregation.FIRST_NON_EMPTY, required_parameters=("name", "imdbid", "mtype", "year", "season", "raise_exception")),
|
||||
"match_tmdbinfo": ModuleMethodContract(family="media-recognition", input_contract="TmdbMatchRequest", result_contract="dict[str, Any] | None", result_shape=ModuleResultShape.MAPPING, aggregation=ModuleResultAggregation.FIRST_NON_EMPTY, required_parameters=("name", "mtype", "year", "season")),
|
||||
"update_recognize_cache": ModuleMethodContract(family="media-recognition", input_contract="RecognitionCacheUpdateRequest", result_contract="bool | None", result_shape=ModuleResultShape.BOOLEAN, aggregation=ModuleResultAggregation.FIRST_NON_EMPTY, required_parameters=("meta", "mediainfo")),
|
||||
"search_medias": ModuleMethodContract(
|
||||
family="media-recognition", input_contract="MediaSearchRequest",
|
||||
result_contract="list[MediaInfo]", result_shape=ModuleResultShape.LIST,
|
||||
@@ -217,6 +220,7 @@ _METHOD_CONTRACTS = {
|
||||
"download_wechat_media_bytes": ModuleMethodContract(family="messaging", input_contract="MessageMediaDownloadRequest", result_contract="bytes | None", result_shape=ModuleResultShape.BYTES, aggregation=ModuleResultAggregation.FIRST_NON_EMPTY, required_parameters=("media_ref", "source")),
|
||||
"downloader_info": ModuleMethodContract(family="downloader", input_contract="DownloaderInfoRequest", result_contract="list[DownloaderInfo]", result_shape=ModuleResultShape.LIST, aggregation=ModuleResultAggregation.ORDERED_LIST_MERGE, required_parameters=("downloader",)),
|
||||
"list_torrents": ModuleMethodContract(family="downloader", input_contract="TorrentListRequest", result_contract="list[DownloaderTorrent]", result_shape=ModuleResultShape.LIST, aggregation=ModuleResultAggregation.ORDERED_LIST_MERGE, required_parameters=("status", "hashs", "downloader", "include_all_tags")),
|
||||
"filter_torrents": ModuleMethodContract(family="downloader", input_contract="TorrentFilterRequest", result_contract="list[TorrentInfo]", result_shape=ModuleResultShape.LIST, aggregation=ModuleResultAggregation.ORDERED_LIST_MERGE, required_parameters=("rule_groups", "torrent_list", "mediainfo")),
|
||||
"refresh_torrents": ModuleMethodContract(family="downloader", input_contract="TorrentRefreshRequest", result_contract="list[TorrentInfo]", result_shape=ModuleResultShape.LIST, aggregation=ModuleResultAggregation.ORDERED_LIST_MERGE, required_parameters=("site", "keyword", "cat", "page", "mtype")),
|
||||
"torrent_files": ModuleMethodContract(family="downloader", input_contract="TorrentFilesRequest", result_contract="DownloaderFileCollection | None", required_parameters=("tid", "downloader")),
|
||||
"get_torrent_trackers": ModuleMethodContract(family="downloader", input_contract="TorrentTrackersRequest", result_contract="dict[str, list[str]] | None", result_shape=ModuleResultShape.MAPPING, aggregation=ModuleResultAggregation.ORDERED_MAPPING_MERGE, required_parameters=("hash_string", "downloader")),
|
||||
@@ -233,6 +237,9 @@ _METHOD_CONTRACTS = {
|
||||
# 同一能力的同步/异步入口共享不可变契约对象,避免参数和聚合语义各自漂移。
|
||||
_METHOD_CONTRACTS.update({
|
||||
"async_recognize_media": _METHOD_CONTRACTS["recognize_media"],
|
||||
"async_match_doubaninfo": _METHOD_CONTRACTS["match_doubaninfo"],
|
||||
"async_match_tmdbinfo": _METHOD_CONTRACTS["match_tmdbinfo"],
|
||||
"async_update_recognize_cache": _METHOD_CONTRACTS["update_recognize_cache"],
|
||||
"async_search_medias": _METHOD_CONTRACTS["search_medias"],
|
||||
"async_obtain_images": _METHOD_CONTRACTS["obtain_images"],
|
||||
"async_movie_hot": _METHOD_CONTRACTS["movie_hot"],
|
||||
|
||||
+69
-35
@@ -2958,16 +2958,23 @@
|
||||
"version": 1
|
||||
},
|
||||
"async_match_doubaninfo": {
|
||||
"aggregation": "legacy",
|
||||
"aggregation": "first_non_empty",
|
||||
"error_policy": "isolate_provider",
|
||||
"execution": "sync_or_async",
|
||||
"family": "media-recognition",
|
||||
"input_contract": "MediaRecognitionKeywordArguments",
|
||||
"input_contract": "DoubanMatchRequest",
|
||||
"plugin_short_circuit": true,
|
||||
"public_to_plugins": true,
|
||||
"required_parameters": [],
|
||||
"result_contract": "MediaRecognitionProviderResult",
|
||||
"result_shape": "any",
|
||||
"required_parameters": [
|
||||
"imdbid",
|
||||
"mtype",
|
||||
"name",
|
||||
"raise_exception",
|
||||
"season",
|
||||
"year"
|
||||
],
|
||||
"result_contract": "dict[str, Any] | None",
|
||||
"result_shape": "mapping",
|
||||
"supports_async": true,
|
||||
"supports_sync": true,
|
||||
"timeout_policy": "caller_budget",
|
||||
@@ -2994,16 +3001,21 @@
|
||||
"version": 1
|
||||
},
|
||||
"async_match_tmdbinfo": {
|
||||
"aggregation": "legacy",
|
||||
"aggregation": "first_non_empty",
|
||||
"error_policy": "isolate_provider",
|
||||
"execution": "sync_or_async",
|
||||
"family": "media-recognition",
|
||||
"input_contract": "MediaRecognitionKeywordArguments",
|
||||
"input_contract": "TmdbMatchRequest",
|
||||
"plugin_short_circuit": true,
|
||||
"public_to_plugins": true,
|
||||
"required_parameters": [],
|
||||
"result_contract": "MediaRecognitionProviderResult",
|
||||
"result_shape": "any",
|
||||
"required_parameters": [
|
||||
"mtype",
|
||||
"name",
|
||||
"season",
|
||||
"year"
|
||||
],
|
||||
"result_contract": "dict[str, Any] | None",
|
||||
"result_shape": "mapping",
|
||||
"supports_async": true,
|
||||
"supports_sync": true,
|
||||
"timeout_policy": "caller_budget",
|
||||
@@ -3590,16 +3602,19 @@
|
||||
"version": 1
|
||||
},
|
||||
"async_update_recognize_cache": {
|
||||
"aggregation": "legacy",
|
||||
"aggregation": "first_non_empty",
|
||||
"error_policy": "isolate_provider",
|
||||
"execution": "sync_or_async",
|
||||
"family": "media-recognition",
|
||||
"input_contract": "MediaRecognitionKeywordArguments",
|
||||
"input_contract": "RecognitionCacheUpdateRequest",
|
||||
"plugin_short_circuit": true,
|
||||
"public_to_plugins": true,
|
||||
"required_parameters": [],
|
||||
"result_contract": "MediaRecognitionProviderResult",
|
||||
"result_shape": "any",
|
||||
"required_parameters": [
|
||||
"mediainfo",
|
||||
"meta"
|
||||
],
|
||||
"result_contract": "bool | None",
|
||||
"result_shape": "boolean",
|
||||
"supports_async": true,
|
||||
"supports_sync": true,
|
||||
"timeout_policy": "caller_budget",
|
||||
@@ -4321,16 +4336,20 @@
|
||||
"version": 1
|
||||
},
|
||||
"filter_torrents": {
|
||||
"aggregation": "legacy",
|
||||
"aggregation": "ordered_list_merge",
|
||||
"error_policy": "isolate_provider",
|
||||
"execution": "sync_or_async",
|
||||
"family": "downloader",
|
||||
"input_contract": "DownloaderKeywordArguments",
|
||||
"input_contract": "TorrentFilterRequest",
|
||||
"plugin_short_circuit": true,
|
||||
"public_to_plugins": true,
|
||||
"required_parameters": [],
|
||||
"result_contract": "DownloaderProviderResult",
|
||||
"result_shape": "any",
|
||||
"required_parameters": [
|
||||
"mediainfo",
|
||||
"rule_groups",
|
||||
"torrent_list"
|
||||
],
|
||||
"result_contract": "list[TorrentInfo]",
|
||||
"result_shape": "list",
|
||||
"supports_async": true,
|
||||
"supports_sync": true,
|
||||
"timeout_policy": "caller_budget",
|
||||
@@ -4569,16 +4588,23 @@
|
||||
"version": 1
|
||||
},
|
||||
"match_doubaninfo": {
|
||||
"aggregation": "legacy",
|
||||
"aggregation": "first_non_empty",
|
||||
"error_policy": "isolate_provider",
|
||||
"execution": "sync_or_async",
|
||||
"family": "media-recognition",
|
||||
"input_contract": "MediaRecognitionKeywordArguments",
|
||||
"input_contract": "DoubanMatchRequest",
|
||||
"plugin_short_circuit": true,
|
||||
"public_to_plugins": true,
|
||||
"required_parameters": [],
|
||||
"result_contract": "MediaRecognitionProviderResult",
|
||||
"result_shape": "any",
|
||||
"required_parameters": [
|
||||
"imdbid",
|
||||
"mtype",
|
||||
"name",
|
||||
"raise_exception",
|
||||
"season",
|
||||
"year"
|
||||
],
|
||||
"result_contract": "dict[str, Any] | None",
|
||||
"result_shape": "mapping",
|
||||
"supports_async": true,
|
||||
"supports_sync": true,
|
||||
"timeout_policy": "caller_budget",
|
||||
@@ -4605,16 +4631,21 @@
|
||||
"version": 1
|
||||
},
|
||||
"match_tmdbinfo": {
|
||||
"aggregation": "legacy",
|
||||
"aggregation": "first_non_empty",
|
||||
"error_policy": "isolate_provider",
|
||||
"execution": "sync_or_async",
|
||||
"family": "media-recognition",
|
||||
"input_contract": "MediaRecognitionKeywordArguments",
|
||||
"input_contract": "TmdbMatchRequest",
|
||||
"plugin_short_circuit": true,
|
||||
"public_to_plugins": true,
|
||||
"required_parameters": [],
|
||||
"result_contract": "MediaRecognitionProviderResult",
|
||||
"result_shape": "any",
|
||||
"required_parameters": [
|
||||
"mtype",
|
||||
"name",
|
||||
"season",
|
||||
"year"
|
||||
],
|
||||
"result_contract": "dict[str, Any] | None",
|
||||
"result_shape": "mapping",
|
||||
"supports_async": true,
|
||||
"supports_sync": true,
|
||||
"timeout_policy": "caller_budget",
|
||||
@@ -6281,16 +6312,19 @@
|
||||
"version": 1
|
||||
},
|
||||
"update_recognize_cache": {
|
||||
"aggregation": "legacy",
|
||||
"aggregation": "first_non_empty",
|
||||
"error_policy": "isolate_provider",
|
||||
"execution": "sync_or_async",
|
||||
"family": "media-recognition",
|
||||
"input_contract": "MediaRecognitionKeywordArguments",
|
||||
"input_contract": "RecognitionCacheUpdateRequest",
|
||||
"plugin_short_circuit": true,
|
||||
"public_to_plugins": true,
|
||||
"required_parameters": [],
|
||||
"result_contract": "MediaRecognitionProviderResult",
|
||||
"result_shape": "any",
|
||||
"required_parameters": [
|
||||
"mediainfo",
|
||||
"meta"
|
||||
],
|
||||
"result_contract": "bool | None",
|
||||
"result_shape": "boolean",
|
||||
"supports_async": true,
|
||||
"supports_sync": true,
|
||||
"timeout_policy": "caller_budget",
|
||||
|
||||
@@ -268,6 +268,36 @@ def test_lookup_contracts_separate_value_routes_from_list_aggregation() -> None:
|
||||
assert contract.result_contract
|
||||
|
||||
|
||||
def test_recognition_match_and_cache_contracts_share_sync_async_semantics() -> None:
|
||||
"""媒体匹配与缓存回填的同步、异步入口必须复用同一目标路由契约。"""
|
||||
pairs = {
|
||||
"match_doubaninfo": "async_match_doubaninfo",
|
||||
"match_tmdbinfo": "async_match_tmdbinfo",
|
||||
"update_recognize_cache": "async_update_recognize_cache",
|
||||
}
|
||||
|
||||
for sync_method, async_method in pairs.items():
|
||||
contract = get_module_method_contract(sync_method)
|
||||
assert contract is get_module_method_contract(async_method)
|
||||
assert contract.family == "media-recognition"
|
||||
assert contract.aggregation is ModuleResultAggregation.FIRST_NON_EMPTY
|
||||
assert contract.required_parameters
|
||||
|
||||
|
||||
def test_torrent_filter_contract_preserves_original_argument_list_merge() -> None:
|
||||
"""种子过滤 provider 应接收原始参数并有序合并结果,不得误用单参数接力。"""
|
||||
contract = get_module_method_contract("filter_torrents")
|
||||
|
||||
assert contract.family == "downloader"
|
||||
assert contract.aggregation is ModuleResultAggregation.ORDERED_LIST_MERGE
|
||||
assert contract.result_shape is ModuleResultShape.LIST
|
||||
assert contract.required_parameters == (
|
||||
"rule_groups",
|
||||
"torrent_list",
|
||||
"mediainfo",
|
||||
)
|
||||
|
||||
|
||||
def test_heterogeneous_torrent_files_result_remains_legacy_compatible() -> None:
|
||||
"""下载器文件集合尚未归一前不得声明虚假的列表聚合语义。"""
|
||||
contract = get_module_method_contract("torrent_files")
|
||||
|
||||
Reference in New Issue
Block a user