mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-01 04:47:03 +08:00
fix(feishu): 补充资源选择卡片的站点、大小和做种数 (#7085)
* fix(feishu): show site size and seeders in torrent cards * chore(architecture): record Feishu size formatting dependency
This commit is contained in:
@@ -19,6 +19,7 @@ from app.application.messaging.channel.admin import matches_channel_admin
|
||||
from app.application.messaging.ingress import submit_message_to_host
|
||||
from app.application.security.user import get_configured_user_channel_lookup
|
||||
from app.domain.context import Context, MediaInfo
|
||||
from app.foundation import size as size_tools
|
||||
from app.modules.feishu.openapi import FEISHU_DOMAIN, FeishuOpenApi, FeishuResponse, JsonDict
|
||||
from app.runtime.log import logger
|
||||
from app.runtime.settings import get_runtime_setting
|
||||
@@ -2071,6 +2072,8 @@ class Feishu:
|
||||
"""
|
||||
将前 10 个种子候选项渲染为通知卡片。
|
||||
|
||||
每项显示站点、标题、大小和做种数;缺失或为零的详情不展示,保留输入顺序与选择序号。
|
||||
|
||||
:param message: 原通知标题、按钮、链接和目标
|
||||
:param torrents: 含种子信息的候选上下文
|
||||
:param userid: 显式用户标识;未提供用户和会话时回退到默认配置或已互动会话
|
||||
@@ -2082,7 +2085,16 @@ class Feishu:
|
||||
for index, torrent in enumerate(torrents[:10], start=1):
|
||||
torrent_info = getattr(torrent, "torrent_info", None)
|
||||
title = getattr(torrent_info, "title", None) or getattr(torrent_info, "site_name", None) or "未知种子"
|
||||
lines.append(f"{index}. {title}")
|
||||
site_name = getattr(torrent_info, "site_name", None)
|
||||
size = getattr(torrent_info, "size", None)
|
||||
seeders = getattr(torrent_info, "seeders", None)
|
||||
site_prefix = f"【{site_name}】" if site_name else " "
|
||||
details = [f"{index}.{site_prefix}{title}"]
|
||||
if size:
|
||||
details.append(size_tools.format_compact_size(size))
|
||||
if seeders:
|
||||
details.append(f"{seeders}↑")
|
||||
lines.append(" ".join(details))
|
||||
proxy_message = Message(
|
||||
title=message.title,
|
||||
text="\n".join(lines),
|
||||
|
||||
@@ -817,7 +817,7 @@ flowchart LR
|
||||
| 指标 | 当前值 |
|
||||
|---|---:|
|
||||
| Python 模块 | 1127 |
|
||||
| 内部导入边 | 9,640 |
|
||||
| 内部导入边 | 9,642 |
|
||||
| 非平凡 SCC | 1(29 个模块的 TMDB vendor 精确 containment) |
|
||||
| Application / Chain 具体 Adapter 直连 | 0 / 0 |
|
||||
| Direct egress | 51(精确 policy 准入,Application / Chain 均为 0) |
|
||||
|
||||
@@ -975,8 +975,8 @@
|
||||
"runtime_only": true
|
||||
}
|
||||
},
|
||||
"edge_count": 9640,
|
||||
"edge_sha256": "e282d6307ea8c6f0cd2843f5c2faae04995bc2630c945e408d1dd490e337fcfe",
|
||||
"edge_count": 9642,
|
||||
"edge_sha256": "bace4b8791f142f8d9fdc9e12f532c562d7eec5bed42adb2d07bdb9c8ec8251a",
|
||||
"edges": [
|
||||
"app -> app.foundation",
|
||||
"app -> app.foundation.environment",
|
||||
@@ -7323,6 +7323,8 @@
|
||||
"app.modules.feishu.feishu -> app.application.security.user",
|
||||
"app.modules.feishu.feishu -> app.domain",
|
||||
"app.modules.feishu.feishu -> app.domain.context",
|
||||
"app.modules.feishu.feishu -> app.foundation",
|
||||
"app.modules.feishu.feishu -> app.foundation.size",
|
||||
"app.modules.feishu.feishu -> app.modules",
|
||||
"app.modules.feishu.feishu -> app.modules.feishu",
|
||||
"app.modules.feishu.feishu -> app.modules.feishu.openapi",
|
||||
|
||||
95
tests/test_feishu_torrents_message.py
Normal file
95
tests/test_feishu_torrents_message.py
Normal file
@@ -0,0 +1,95 @@
|
||||
"""
|
||||
验证飞书资源选择卡片的种子详情、缺失字段和选择按钮。
|
||||
"""
|
||||
|
||||
import json
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from app.domain.context import Context
|
||||
from app.modules.feishu.feishu import Feishu
|
||||
from app.modules.feishu.openapi import FeishuOpenApi, FeishuResponse
|
||||
from app.schemas.context import TorrentInfo
|
||||
from app.schemas.message import Message
|
||||
|
||||
|
||||
def _build_client() -> tuple[Feishu, MagicMock]:
|
||||
"""
|
||||
构造隔离长连接与开放平台请求的客户端,保留真实卡片渲染路径。
|
||||
"""
|
||||
api = MagicMock(spec=FeishuOpenApi)
|
||||
api.create_message.return_value = FeishuResponse(
|
||||
code=0, msg="success", data={"message_id": "om_test", "chat_id": "oc_test"},
|
||||
)
|
||||
with (
|
||||
patch.object(Feishu, "_build_api_client", return_value=api),
|
||||
patch.object(Feishu, "_start_ws_client"),
|
||||
):
|
||||
client = Feishu(FEISHU_APP_ID="test_app", FEISHU_APP_SECRET="test_secret")
|
||||
return client, api
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("fields", "expected"),
|
||||
[
|
||||
({"site_name": "站点", "size": 2.5 * 1024 ** 3, "seeders": 35}, "1.【站点】影片 2.5G 35↑"),
|
||||
({"site_name": "站点", "size": 2.5 * 1024 ** 3}, "1.【站点】影片 2.5G"),
|
||||
({"site_name": "站点", "seeders": 35}, "1.【站点】影片 35↑"),
|
||||
({"size": 2.5 * 1024 ** 3, "seeders": 35}, "1. 影片 2.5G 35↑"),
|
||||
({"site_name": "站点"}, "1.【站点】影片"),
|
||||
({"size": 2.5 * 1024 ** 3}, "1. 影片 2.5G"),
|
||||
({"seeders": 35}, "1. 影片 35↑"),
|
||||
({}, "1. 影片"),
|
||||
({"site_name": None, "size": None, "seeders": None}, "1. 影片"),
|
||||
({"site_name": "", "size": 0, "seeders": 0}, "1. 影片"),
|
||||
({"title": None, "site_name": "站点"}, "1.【站点】站点"),
|
||||
({"title": None}, "1. 未知种子"),
|
||||
],
|
||||
)
|
||||
def test_torrent_card_displays_available_details(fields: dict, expected: str) -> None:
|
||||
"""
|
||||
实际发送的卡片显示可用站点、大小和做种数,省略空值且不附加促销文案。
|
||||
"""
|
||||
client, api = _build_client()
|
||||
torrent = TorrentInfo(**{"title": "影片", "volume_factor": "免费", **fields})
|
||||
|
||||
result = client.send_torrents_message(
|
||||
Message(title="请选择下载"), [Context(torrent_info=torrent)], userid="ou_user",
|
||||
)
|
||||
|
||||
assert result["success"]
|
||||
card = json.loads(api.create_message.call_args.kwargs["content"])
|
||||
assert card["body"]["elements"][1]["content"] == expected
|
||||
|
||||
|
||||
def test_torrent_card_keeps_selection_order_and_target() -> None:
|
||||
"""
|
||||
列表仅展示前十项,缺失种子信息仍保留序号,接收会话、链接和下载按钮保持可用。
|
||||
"""
|
||||
client, api = _build_client()
|
||||
torrents = [Context()] + [
|
||||
Context(torrent_info=TorrentInfo(title=f"影片{index}", seeders=index))
|
||||
for index in range(2, 12)
|
||||
]
|
||||
result = client.send_torrents_message(
|
||||
Message(
|
||||
title="请选择下载", link="https://example.com/search",
|
||||
buttons=[[{"text": "下载第2项", "callback_data": "2"}]],
|
||||
),
|
||||
torrents, chat_id="oc_target", receive_id_type="chat_id",
|
||||
)
|
||||
|
||||
assert result["success"]
|
||||
request = api.create_message.call_args.kwargs
|
||||
assert request["receive_id"] == "oc_target"
|
||||
assert request["receive_id_type"] == "chat_id"
|
||||
card = json.loads(request["content"])
|
||||
content = card["body"]["elements"][1]["content"]
|
||||
assert content.splitlines()[:10] == ["1. 未知种子"] + [
|
||||
f"{index}. 影片{index} {index}↑" for index in range(2, 11)
|
||||
]
|
||||
assert "影片11" not in content
|
||||
assert "https://example.com/search" in content
|
||||
button = card["body"]["elements"][-1]["columns"][0]["elements"][0]
|
||||
assert button["behaviors"] == [{"type": "callback", "value": {"callback_data": "2"}}]
|
||||
Reference in New Issue
Block a user