From 89530263f26868cf2da92a70972e6d5032fb8c37 Mon Sep 17 00:00:00 2001 From: zj1123581321 Date: Mon, 14 Sep 2026 20:26:32 +0800 Subject: [PATCH 1/8] feat: add variants to VideoInfo cache payload Agent-Executor: codex Agent-Model: gpt-5.6-luna Agent-Effort: xhigh Dispatch-Id: dlg-20260914-122425-3250c5 Task-Id: MediaResolverAPI-20260914-06 --- app/services/platforms/base.py | 2 ++ .../resolve-intent/progress/twitter-variants-progress.md | 6 ++++++ 2 files changed, 8 insertions(+) create mode 100644 docs/sessions/resolve-intent/progress/twitter-variants-progress.md diff --git a/app/services/platforms/base.py b/app/services/platforms/base.py index 6f92079..154fd74 100644 --- a/app/services/platforms/base.py +++ b/app/services/platforms/base.py @@ -31,6 +31,7 @@ class VideoInfo: duration: Optional[int] = None quality: Optional[str] = None media_type: str = "video" + variants: Optional[list[Dict[str, Any]]] = None # 统计信息 view_count: Optional[int] = None @@ -64,6 +65,7 @@ def to_dict(self) -> Dict[str, Any]: 'duration': self.duration, 'quality': self.quality, 'media_type': self.media_type, + 'variants': self.variants, 'view_count': self.view_count, 'like_count': self.like_count, 'comment_count': self.comment_count, diff --git a/docs/sessions/resolve-intent/progress/twitter-variants-progress.md b/docs/sessions/resolve-intent/progress/twitter-variants-progress.md new file mode 100644 index 0000000..ea0d3ec --- /dev/null +++ b/docs/sessions/resolve-intent/progress/twitter-variants-progress.md @@ -0,0 +1,6 @@ +## 2026-09-14 — VideoInfo contract + +- 当前阶段:implementing — VideoInfo + to_dict +- 本段结论:为统一视频信息增加可选 `variants` 字段,并让缓存序列化带出该键;既有构造方不受影响。 +- 关键决策与已否决方案:沿用任务卡的附加可选字段契约,不增加开关或兼容分支。 +- 下一步唯一动作:在 Twitter 解析层从既有 candidates 构造全部 mp4 variants。 From 71df21bd85e0b7fc532d1b5de0f23b25b6467edb Mon Sep 17 00:00:00 2001 From: zj1123581321 Date: Mon, 14 Sep 2026 20:26:56 +0800 Subject: [PATCH 2/8] feat: expose Twitter mp4 variants from parser Agent-Executor: codex Agent-Model: gpt-5.6-luna Agent-Effort: xhigh Dispatch-Id: dlg-20260914-122425-3250c5 Task-Id: MediaResolverAPI-20260914-06 --- app/services/platforms/twitter.py | 19 +++++++++++++++++++ .../progress/twitter-variants-progress.md | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/app/services/platforms/twitter.py b/app/services/platforms/twitter.py index 07f0dd5..46297bd 100644 --- a/app/services/platforms/twitter.py +++ b/app/services/platforms/twitter.py @@ -49,6 +49,24 @@ def _parse_response( if not candidates: return None + variants = [ + { + "url": str(candidate[0]["url"]), + "bitrate": candidate[5] if candidate[5] > 0 else None, + "width": candidate[2], + "height": candidate[3], + "quality": f"{candidate[3]}p" if candidate[3] > 0 else None, + } + for candidate in sorted( + candidates, + key=lambda candidate: ( + candidate[5] <= 0, + candidate[5] if candidate[5] > 0 else 0, + candidate[4], + ), + ) + ] + if quality is None: selected = self._select_default_variant(candidates) else: @@ -97,6 +115,7 @@ def _parse_response( height=height, duration=duration, quality=f"{height}p", + variants=variants, view_count=self._parse_count(data.get("views")), like_count=self._parse_count(data.get("likes")), comment_count=self._parse_count(data.get("replies")), diff --git a/docs/sessions/resolve-intent/progress/twitter-variants-progress.md b/docs/sessions/resolve-intent/progress/twitter-variants-progress.md index ea0d3ec..7d8a34d 100644 --- a/docs/sessions/resolve-intent/progress/twitter-variants-progress.md +++ b/docs/sessions/resolve-intent/progress/twitter-variants-progress.md @@ -4,3 +4,10 @@ - 本段结论:为统一视频信息增加可选 `variants` 字段,并让缓存序列化带出该键;既有构造方不受影响。 - 关键决策与已否决方案:沿用任务卡的附加可选字段契约,不增加开关或兼容分支。 - 下一步唯一动作:在 Twitter 解析层从既有 candidates 构造全部 mp4 variants。 + +## 2026-09-14 — Twitter parsing + +- 当前阶段:implementing — Twitter 解析层 +- 本段结论:Twitter 解析现在把 candidates 中的全部 mp4 variant 映射为 url、bitrate、width、height、quality,并按码率升序输出;HLS 仍不进入 candidates,主选流逻辑未变。 +- 关键决策与已否决方案:无 +- 下一步唯一动作:把 variants 接入缓存命中重建路径。 From e257a9e3257d3aabdb7cb2842d0624ae89f22c54 Mon Sep 17 00:00:00 2001 From: zj1123581321 Date: Mon, 14 Sep 2026 20:27:10 +0800 Subject: [PATCH 3/8] feat: preserve Twitter variants through cache Agent-Executor: codex Agent-Model: gpt-5.6-luna Agent-Effort: xhigh Dispatch-Id: dlg-20260914-122425-3250c5 Task-Id: MediaResolverAPI-20260914-06 --- app/services/cache.py | 1 + .../resolve-intent/progress/twitter-variants-progress.md | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/app/services/cache.py b/app/services/cache.py index f09d6f8..58e353a 100644 --- a/app/services/cache.py +++ b/app/services/cache.py @@ -87,6 +87,7 @@ def get_cached_video( duration=cached_data.get("duration"), quality=cached_data.get("quality"), media_type=cached_data.get("media_type", "video"), + variants=cached_data.get("variants"), view_count=cached_data.get("view_count"), like_count=cached_data.get("like_count"), comment_count=cached_data.get("comment_count"), diff --git a/docs/sessions/resolve-intent/progress/twitter-variants-progress.md b/docs/sessions/resolve-intent/progress/twitter-variants-progress.md index 7d8a34d..8b85cd6 100644 --- a/docs/sessions/resolve-intent/progress/twitter-variants-progress.md +++ b/docs/sessions/resolve-intent/progress/twitter-variants-progress.md @@ -11,3 +11,10 @@ - 本段结论:Twitter 解析现在把 candidates 中的全部 mp4 variant 映射为 url、bitrate、width、height、quality,并按码率升序输出;HLS 仍不进入 candidates,主选流逻辑未变。 - 关键决策与已否决方案:无 - 下一步唯一动作:把 variants 接入缓存命中重建路径。 + +## 2026-09-14 — Cache round-trip + +- 当前阶段:implementing — cache 回环 +- 本段结论:缓存重建从序列化数据透传 `variants`,旧缓存行没有该键时自然得到 `None`;新缓存数据可完整回环。 +- 关键决策与已否决方案:沿用任务卡约定,不添加旧行回填或额外兼容分支。 +- 下一步唯一动作:增加 API 响应模型和 `_build_response` 的 variants 映射。 From 8814ac392b86d4addb5798ef736f8f70f9c7dd40 Mon Sep 17 00:00:00 2001 From: zj1123581321 Date: Mon, 14 Sep 2026 20:27:34 +0800 Subject: [PATCH 4/8] feat: map video variants in resolve response Agent-Executor: codex Agent-Model: gpt-5.6-luna Agent-Effort: xhigh Dispatch-Id: dlg-20260914-122425-3250c5 Task-Id: MediaResolverAPI-20260914-06 --- app/api/resolve.py | 25 +++++++++++++++++++ .../progress/twitter-variants-progress.md | 7 ++++++ 2 files changed, 32 insertions(+) diff --git a/app/api/resolve.py b/app/api/resolve.py index 26c55f8..ae5ab47 100644 --- a/app/api/resolve.py +++ b/app/api/resolve.py @@ -81,6 +81,16 @@ def reject_quality_for_audio(self): return self +class VideoVariant(BaseModel): + """A playable MP4 variant exposed for downstream stream selection.""" + + url: str + bitrate: Optional[int] = None + width: int = 0 + height: int = 0 + quality: Optional[str] = None + + class VideoInfoResponse(BaseModel): """Video info in the response.""" @@ -98,6 +108,7 @@ class VideoInfoResponse(BaseModel): height: int duration: Optional[int] = None quality: Optional[str] = None + variants: Optional[list[VideoVariant]] = None view_count: Optional[int] = None like_count: Optional[int] = None comment_count: Optional[int] = None @@ -367,6 +378,20 @@ def _build_response( height=video_info.height, duration=video_info.duration, quality=video_info.quality, + variants=( + [ + VideoVariant( + url=_absolutize_video_url(variant["url"], public_origin), + bitrate=variant.get("bitrate"), + width=variant.get("width", 0), + height=variant.get("height", 0), + quality=variant.get("quality"), + ) + for variant in video_info.variants + ] + if video_info.variants is not None + else None + ), view_count=video_info.view_count, like_count=video_info.like_count, comment_count=video_info.comment_count, diff --git a/docs/sessions/resolve-intent/progress/twitter-variants-progress.md b/docs/sessions/resolve-intent/progress/twitter-variants-progress.md index 8b85cd6..e0e0e38 100644 --- a/docs/sessions/resolve-intent/progress/twitter-variants-progress.md +++ b/docs/sessions/resolve-intent/progress/twitter-variants-progress.md @@ -18,3 +18,10 @@ - 本段结论:缓存重建从序列化数据透传 `variants`,旧缓存行没有该键时自然得到 `None`;新缓存数据可完整回环。 - 关键决策与已否决方案:沿用任务卡约定,不添加旧行回填或额外兼容分支。 - 下一步唯一动作:增加 API 响应模型和 `_build_response` 的 variants 映射。 + +## 2026-09-14 — API response contract + +- 当前阶段:implementing — API 模型与映射 +- 本段结论:新增 `VideoVariant` 和可选 `VideoInfoResponse.variants`,响应映射逐条绝对化 URL;`VideoInfo.variants is None` 时响应字段保持 `null`。 +- 关键决策与已否决方案:variants 只作为常驻附加字段,不增加请求参数或平台分支。 +- 下一步唯一动作:补解析层与 API/缓存回环测试,并先执行未改代码红验。 From 6263dfdbb265f461f1760451d7912f907fb02590 Mon Sep 17 00:00:00 2001 From: zj1123581321 Date: Mon, 14 Sep 2026 20:28:33 +0800 Subject: [PATCH 5/8] test: cover Twitter variants and cache round trip Agent-Executor: codex Agent-Model: gpt-5.6-luna Agent-Effort: xhigh Dispatch-Id: dlg-20260914-122425-3250c5 Task-Id: MediaResolverAPI-20260914-06 --- .../progress/twitter-variants-progress.md | 7 ++ tests/test_resolve_quality.py | 73 +++++++++++++++++ tests/test_tikhub_provider_twitter.py | 82 +++++++++++++++++++ 3 files changed, 162 insertions(+) diff --git a/docs/sessions/resolve-intent/progress/twitter-variants-progress.md b/docs/sessions/resolve-intent/progress/twitter-variants-progress.md index e0e0e38..3648cd0 100644 --- a/docs/sessions/resolve-intent/progress/twitter-variants-progress.md +++ b/docs/sessions/resolve-intent/progress/twitter-variants-progress.md @@ -25,3 +25,10 @@ - 本段结论:新增 `VideoVariant` 和可选 `VideoInfoResponse.variants`,响应映射逐条绝对化 URL;`VideoInfo.variants is None` 时响应字段保持 `null`。 - 关键决策与已否决方案:variants 只作为常驻附加字段,不增加请求参数或平台分支。 - 下一步唯一动作:补解析层与 API/缓存回环测试,并先执行未改代码红验。 + +## 2026-09-14 — Tests + +- 当前阶段:implementing — 测试 +- 本段结论:新增解析层完整 mp4、排序/非法码率测试,以及 API force-refresh 与缓存命中逐一相等的 X variants 断言;同时锁定非 Twitter 响应为 `null`。 +- 关键决策与已否决方案:无 +- 下一步唯一动作:完成 README 字段表与示例,并执行红验和全量测试。 diff --git a/tests/test_resolve_quality.py b/tests/test_resolve_quality.py index d3c9bab..d76483a 100644 --- a/tests/test_resolve_quality.py +++ b/tests/test_resolve_quality.py @@ -341,6 +341,7 @@ async def tikhub_fetch(*args, **kwargs): assert response_720.json()["data"]["video_url"].endswith("youtube-720-high.mp4") assert response_1080.status_code == 200 assert response_1080.json()["data"]["video_url"].endswith("youtube-1080.mp4") + assert response_720.json()["data"]["variants"] is None assert cached_720.json()["data"]["video_url"].endswith("youtube-720-high.mp4") assert calls == ["720p", "1080p"] assert { @@ -349,6 +350,78 @@ async def tikhub_fetch(*args, **kwargs): } == {"720p", "1080p"} +def test_api_twitter_variants_survive_cache_round_trip( + authed_client, monkeypatch +): + monkeypatch.setattr(resolve_mod.url_parser, "is_short_url", lambda _url: False) + monkeypatch.setattr( + resolve_mod.url_parser, + "parse_url", + lambda _url: ("twitter", "twitter-variants"), + ) + resolver = VideoResolver() + calls = [] + + async def tikhub_fetch(*args, **kwargs): + calls.append(kwargs) + return _load_platform("twitter", "tweet_video") + + monkeypatch.setattr(resolver.tikhub_provider, "fetch_video_info", tikhub_fetch) + monkeypatch.setattr(resolve_mod, "get_video_resolver", lambda: resolver) + + first = authed_client.post( + "/api/resolve", + json={ + "url": "https://x.com/0xCodez/status/twitter-variants", + "translate": False, + "force_refresh": True, + }, + ) + cached = authed_client.post( + "/api/resolve", + json={ + "url": "https://x.com/0xCodez/status/twitter-variants", + "translate": False, + }, + ) + + assert first.status_code == 200 + assert cached.status_code == 200 + first_variants = first.json()["data"]["variants"] + assert first_variants == [ + { + "url": "https://video.twimg.com/amplify_video/fake/avc1/480x270/twitter_270.mp4", + "bitrate": 256000, + "width": 480, + "height": 270, + "quality": "270p", + }, + { + "url": "https://video.twimg.com/amplify_video/fake/avc1/640x360/twitter_360.mp4", + "bitrate": 832000, + "width": 640, + "height": 360, + "quality": "360p", + }, + { + "url": "https://video.twimg.com/amplify_video/fake/avc1/1280x720/twitter_720.mp4", + "bitrate": 2176000, + "width": 1280, + "height": 720, + "quality": "720p", + }, + { + "url": "https://video.twimg.com/amplify_video/fake/avc1/1920x1080/twitter_1080.mp4", + "bitrate": 10368000, + "width": 1920, + "height": 1080, + "quality": "1080p", + }, + ] + assert cached.json()["data"]["variants"] == first_variants + assert len(calls) == 1 + + def test_douyin_fixture_quality_cap_selects_available_lower_stream(): raw = _load_platform("douyin", "app_v3") default_info = DouyinService("key", "base")._parse_response(raw) diff --git a/tests/test_tikhub_provider_twitter.py b/tests/test_tikhub_provider_twitter.py index 650178b..98378de 100644 --- a/tests/test_tikhub_provider_twitter.py +++ b/tests/test_tikhub_provider_twitter.py @@ -30,6 +30,81 @@ def test_parser_picks_highest_mp4(): assert info.height == 1080 +def test_parser_exposes_all_mp4_variants_sorted_by_bitrate(): + info = TwitterService("k", "b")._parse_response(load("tweet_video")) + + assert info is not None + assert info.variants == [ + { + "url": "https://video.twimg.com/amplify_video/fake/avc1/480x270/twitter_270.mp4", + "bitrate": 256000, + "width": 480, + "height": 270, + "quality": "270p", + }, + { + "url": "https://video.twimg.com/amplify_video/fake/avc1/640x360/twitter_360.mp4", + "bitrate": 832000, + "width": 640, + "height": 360, + "quality": "360p", + }, + { + "url": "https://video.twimg.com/amplify_video/fake/avc1/1280x720/twitter_720.mp4", + "bitrate": 2176000, + "width": 1280, + "height": 720, + "quality": "720p", + }, + { + "url": "https://video.twimg.com/amplify_video/fake/avc1/1920x1080/twitter_1080.mp4", + "bitrate": 10368000, + "width": 1920, + "height": 1080, + "quality": "1080p", + }, + ] + + +def test_parser_sorts_invalid_bitrates_last_and_ties_by_short_side(): + payload = load("tweet_video") + payload["data"]["media"]["video"][0]["variants"] = [ + { + "content_type": "video/mp4", + "bitrate": 0, + "url": "https://video.twimg.com/fake/1920x1080/zero.mp4", + }, + { + "content_type": "video/mp4", + "bitrate": 1000, + "url": "https://video.twimg.com/fake/1280x720/high.mp4", + }, + { + "content_type": "video/mp4", + "bitrate": 1000, + "url": "https://video.twimg.com/fake/640x360/low.mp4", + }, + { + "content_type": "video/mp4", + "bitrate": "unknown", + "url": "https://video.twimg.com/fake/480x270/unknown.mp4", + }, + ] + + info = TwitterService("k", "b")._parse_response(payload) + + assert info is not None + assert [ + (variant["bitrate"], variant["width"], variant["height"]) + for variant in info.variants + ] == [ + (1000, 640, 360), + (1000, 1280, 720), + (None, 480, 270), + (None, 1920, 1080), + ] + + def test_parser_picks_highest_mp4_across_videos(): info = TwitterService("k", "b")._parse_response(load("tweet_multi_video")) assert info is not None @@ -219,6 +294,13 @@ def test_parser_malformed_bitrate_falls_soft_and_prefers_valid(): info = TwitterService("k", "b")._parse_response(payload) assert info is not None assert info.video_url == "https://video.twimg.com/fake_unknown_bitrate.mp4" + assert info.variants == [{ + "url": "https://video.twimg.com/fake_unknown_bitrate.mp4", + "bitrate": None, + "width": 1920, + "height": 1080, + "quality": "1080p", + }] payload["data"]["media"]["video"][0]["variants"].append({ "content_type": "video/mp4", From b4fd3e088d63fc30e1285b063a61b5734cfe8f9d Mon Sep 17 00:00:00 2001 From: zj1123581321 Date: Mon, 14 Sep 2026 20:28:49 +0800 Subject: [PATCH 6/8] docs: describe Twitter variants response field Agent-Executor: codex Agent-Model: gpt-5.6-luna Agent-Effort: xhigh Dispatch-Id: dlg-20260914-122425-3250c5 Task-Id: MediaResolverAPI-20260914-06 --- README.md | 2 ++ .../resolve-intent/progress/twitter-variants-progress.md | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/README.md b/README.md index cbb8012..0520076 100644 --- a/README.md +++ b/README.md @@ -197,6 +197,7 @@ audio 模式不代表 MP3 或其他容器格式,服务不做转码;请使用 "height": 1920, "duration": 30, "quality": "1080p", + "variants": null, "view_count": 100000, "like_count": 5000, "comment_count": 200, @@ -229,6 +230,7 @@ audio 模式不代表 MP3 或其他容器格式,服务不做转码;请使用 | `data.height` | int | 视频高度(像素) | | `data.duration` | int \| null | 视频时长(秒) | | `data.quality` | string \| null | 选中流的实际清晰度档位;Cobalt 链没有逐档元数据时为 `"unknown"` | +| `data.variants` | array \| null | 仅 X(Twitter)video 模式透出全部 mp4 variants,按码率升序(`bitrate` 单位为 bps),供下游自行选择低码率流;其他平台和 audio 模式为 `null` | | `data.view_count` | int \| null | 播放量。视频号恒为 `null`(TikHub 的 `read_count` 恒为 0),不是偶尔缺失 | | `data.like_count` | int \| null | 点赞数 | | `data.comment_count` | int \| null | 评论数 | diff --git a/docs/sessions/resolve-intent/progress/twitter-variants-progress.md b/docs/sessions/resolve-intent/progress/twitter-variants-progress.md index 3648cd0..ec6163e 100644 --- a/docs/sessions/resolve-intent/progress/twitter-variants-progress.md +++ b/docs/sessions/resolve-intent/progress/twitter-variants-progress.md @@ -32,3 +32,10 @@ - 本段结论:新增解析层完整 mp4、排序/非法码率测试,以及 API force-refresh 与缓存命中逐一相等的 X variants 断言;同时锁定非 Twitter 响应为 `null`。 - 关键决策与已否决方案:无 - 下一步唯一动作:完成 README 字段表与示例,并执行红验和全量测试。 + +## 2026-09-14 — Acceptance + +- 当前阶段:completed — 交付文档、红验与全量测试 +- 本段结论:README 的成功响应示例补充 `data.variants: null`,字段表说明 X video 的 mp4 variants、bps 单位、码率升序和下游自选低码率语义;两处红验均以断言失败验证约束有效,全量测试 413 passed。 +- 关键决策与已否决方案:无 +- 下一步唯一动作:写入执行器报告并交给主脑验收。 From 5d79a23e4a01eecdcb7b06e060237aed6f684373 Mon Sep 17 00:00:00 2001 From: zj1123581321 Date: Mon, 14 Sep 2026 20:32:12 +0800 Subject: [PATCH 7/8] test: cover six Twitter variants at API boundary Agent-Executor: codex Agent-Model: gpt-5.6-luna Agent-Effort: xhigh Dispatch-Id: dlg-20260914-122425-3250c5 Task-Id: MediaResolverAPI-20260914-06 --- tests/test_resolve_quality.py | 40 +++++++++-------------------------- 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/tests/test_resolve_quality.py b/tests/test_resolve_quality.py index d76483a..f169075 100644 --- a/tests/test_resolve_quality.py +++ b/tests/test_resolve_quality.py @@ -364,7 +364,7 @@ def test_api_twitter_variants_survive_cache_round_trip( async def tikhub_fetch(*args, **kwargs): calls.append(kwargs) - return _load_platform("twitter", "tweet_video") + return _load_quality("twitter_multi") monkeypatch.setattr(resolver.tikhub_provider, "fetch_video_info", tikhub_fetch) monkeypatch.setattr(resolve_mod, "get_video_resolver", lambda: resolver) @@ -388,36 +388,16 @@ async def tikhub_fetch(*args, **kwargs): assert first.status_code == 200 assert cached.status_code == 200 first_variants = first.json()["data"]["variants"] - assert first_variants == [ - { - "url": "https://video.twimg.com/amplify_video/fake/avc1/480x270/twitter_270.mp4", - "bitrate": 256000, - "width": 480, - "height": 270, - "quality": "270p", - }, - { - "url": "https://video.twimg.com/amplify_video/fake/avc1/640x360/twitter_360.mp4", - "bitrate": 832000, - "width": 640, - "height": 360, - "quality": "360p", - }, - { - "url": "https://video.twimg.com/amplify_video/fake/avc1/1280x720/twitter_720.mp4", - "bitrate": 2176000, - "width": 1280, - "height": 720, - "quality": "720p", - }, - { - "url": "https://video.twimg.com/amplify_video/fake/avc1/1920x1080/twitter_1080.mp4", - "bitrate": 10368000, - "width": 1920, - "height": 1080, - "quality": "1080p", - }, + expected_keys = ("url", "bitrate", "width", "height", "quality") + expected_values = [ + ("https://video.twimg.com/fake/640x360/twitter-360.mp4", 500000, 640, 360, "360p"), + ("https://video.twimg.com/fake/1280x720/twitter-720-low.mp4", 1000000, 1280, 720, "720p"), + ("https://video.twimg.com/fake/1280x720/twitter-720-high.mp4", 2000000, 1280, 720, "720p"), + ("https://video.twimg.com/fake/1920x1080/twitter-1080.mp4", 3000000, 1920, 1080, "1080p"), + ("https://video.twimg.com/fake/2560x1440/twitter-1440.mp4", 4000000, 2560, 1440, "1440p"), + ("https://video.twimg.com/fake/3840x2160/twitter-2160.mp4", 5000000, 3840, 2160, "2160p"), ] + assert first_variants == [dict(zip(expected_keys, values)) for values in expected_values] assert cached.json()["data"]["variants"] == first_variants assert len(calls) == 1 From 3d2cca7980bd77588a7236037b4af6df43cfbe01 Mon Sep 17 00:00:00 2001 From: zj1123581321 Date: Mon, 14 Sep 2026 20:33:13 +0800 Subject: [PATCH 8/8] test: assert cached variants payload Agent-Executor: codex Agent-Model: gpt-5.6-luna Agent-Effort: xhigh Dispatch-Id: dlg-20260914-122425-3250c5 Task-Id: MediaResolverAPI-20260914-06 --- tests/test_resolve_quality.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_resolve_quality.py b/tests/test_resolve_quality.py index f169075..c95e3e6 100644 --- a/tests/test_resolve_quality.py +++ b/tests/test_resolve_quality.py @@ -351,7 +351,7 @@ async def tikhub_fetch(*args, **kwargs): def test_api_twitter_variants_survive_cache_round_trip( - authed_client, monkeypatch + authed_client, db, monkeypatch ): monkeypatch.setattr(resolve_mod.url_parser, "is_short_url", lambda _url: False) monkeypatch.setattr( @@ -388,6 +388,9 @@ async def tikhub_fetch(*args, **kwargs): assert first.status_code == 200 assert cached.status_code == 200 first_variants = first.json()["data"]["variants"] + cached_payload = db.query(VideoCache).filter( + VideoCache.video_id == "twitter-variants" + ).one().video_data expected_keys = ("url", "bitrate", "width", "height", "quality") expected_values = [ ("https://video.twimg.com/fake/640x360/twitter-360.mp4", 500000, 640, 360, "360p"), @@ -398,6 +401,7 @@ async def tikhub_fetch(*args, **kwargs): ("https://video.twimg.com/fake/3840x2160/twitter-2160.mp4", 5000000, 3840, 2160, "2160p"), ] assert first_variants == [dict(zip(expected_keys, values)) for values in expected_values] + assert cached_payload["variants"] == first_variants assert cached.json()["data"]["variants"] == first_variants assert len(calls) == 1