From 72f04eac9ab3b7e835e1618f56a051eed6af49d3 Mon Sep 17 00:00:00 2001 From: zj1123581321 Date: Fri, 16 Oct 2026 13:11:14 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=88=86=E4=BA=AB=E9=A1=B5=E6=9C=89?= =?UTF-8?q?=E5=8D=A1=E7=89=87=E6=97=B6=E8=BE=93=E5=87=BA=20X=20=E5=A4=A7?= =?UTF-8?q?=E5=9B=BE=20Open=20Graph=20=E6=A0=87=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 无卡时 head 与现状一致,不输出 twitter:card / og:image。 Co-authored-by: Cursor Agent-Executor: cursor Agent-Model: cursor-grok-4.6-high Agent-Effort: unknown Dispatch-Id: dlg-20261016-050109-9e5512 Task-Id: VideoTranscriptAPI-20261016-06 --- src/video_transcript_api/api/routes/views.py | 38 ++- src/web/templates/base.html | 1 + src/web/templates/transcript.html | 9 +- tests/og_card/test_view_meta.py | 231 +++++++++++++++++++ 4 files changed, 277 insertions(+), 2 deletions(-) create mode 100644 tests/og_card/test_view_meta.py diff --git a/src/video_transcript_api/api/routes/views.py b/src/video_transcript_api/api/routes/views.py index 9159db8a..4c316a3a 100644 --- a/src/video_transcript_api/api/routes/views.py +++ b/src/video_transcript_api/api/routes/views.py @@ -1528,9 +1528,45 @@ async def view_transcript( if view_data["status"] in _CONTENT_VIEW_STATUSES: stats = await asyncio.to_thread(_prepare_success_view, view_data) + def _read_share_card_for_view() -> tuple[Optional[Dict[str, Any]], Optional[str]]: + """Load a contract-valid share card for the transcript page. + + Runs in a worker thread (SQLite/file IO). Missing dir, missing + json, invalid contract, or a json deleted between load and stat + all mean "no card": callers must not emit twitter/og image tags. + """ + cache_dir = view_data.get("cache_dir") + if not cache_dir: + cache_data = ViewTokenResolver(cache_manager).get_cache_by_view_token( + view_token + ) + cache_dir = (cache_data or {}).get("file_path") + if not cache_dir or not os.path.isdir(cache_dir): + return None, None + card = load_share_card(cache_dir) + if not card: + return None, None + try: + mtime_ns = (Path(cache_dir) / CARD_FILENAME).stat().st_mtime_ns + except FileNotFoundError: + logger.warning( + "分享卡片 JSON 在读取后消失: view_token={}", view_token + ) + return None, None + return card, f"{get_base_url()}/og/{view_token}.png?v={mtime_ns}" + + share_card, og_image_url = await asyncio.to_thread(_read_share_card_for_view) + return templates.TemplateResponse( "transcript.html", - {"request": request, **view_data, "view_token": view_token, "stats": stats}, + { + "request": request, + **view_data, + "view_token": view_token, + "stats": stats, + "share_card": share_card, + "og_image_url": og_image_url, + }, ) except Exception as exc: diff --git a/src/web/templates/base.html b/src/web/templates/base.html index 41ac9e5a..1e0f3bb4 100644 --- a/src/web/templates/base.html +++ b/src/web/templates/base.html @@ -18,6 +18,7 @@ + {% block og_image_meta %}{% endblock %} {% block title %}视频转录查看器{% endblock %}