share OG: 팀명 DB 조회(클럽 리그 한글명) + 문구 갱신 + 썸네일 캐시버스터

- /match/:id OG 프리렌더가 STL/CIN 같은 코드 대신 DB 의 한글 short 팀명을
  사용 (KBO·MLB·MLS 포함). 리그 태그도 제목에 표기
- 설명문을 멀티리그 기준 최신 카피로 갱신
- og:image 에 ?v=2 캐시버스터 — 메신저가 과거 실패/구버전 썸네일을
  캐시한 경우 재수집 유도 (index.html 정적 OG 동일 적용)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jwkim 2026-08-18 09:42:10 +09:00
parent 9b57d56daf
commit 22e2e8c29c
2 changed files with 29 additions and 10 deletions

View File

@ -12,10 +12,14 @@ from __future__ import annotations
import html import html
from fastapi import APIRouter from fastapi import APIRouter, Depends
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from ..config import settings from ..config import settings
from ..database import get_db
from ..models import Match
from ..schedule_data import TEAMS from ..schedule_data import TEAMS
router = APIRouter() router = APIRouter()
@ -51,7 +55,7 @@ def _team_label(code: str | None) -> str:
@router.get("/match/{match_id}", response_class=HTMLResponse) @router.get("/match/{match_id}", response_class=HTMLResponse)
async def match_share(match_id: str) -> HTMLResponse: async def match_share(match_id: str, db: AsyncSession = Depends(get_db)) -> HTMLResponse:
a, b = _parse_codes(match_id) a, b = _parse_codes(match_id)
image = DEFAULT_OG image = DEFAULT_OG
@ -62,19 +66,34 @@ async def match_share(match_id: str) -> HTMLResponse:
image = OG_DIR + OG_IMAGES[key] image = OG_DIR + OG_IMAGES[key]
is_custom = True is_custom = True
# 팀명: DB 의 경기 행이 있으면 한글 short 명(클럽 리그 포함),
# 없으면 월드컵 정적 테이블 → 코드 순으로 폴백.
m = (
await db.execute(select(Match).where(Match.match_id == match_id))
).scalar_one_or_none()
if m:
la, lb = m.team_a_short, m.team_b_short
a, b = m.team_a_code, m.team_b_code
else:
la, lb = _team_label(a), _team_label(b) la, lb = _team_label(a), _team_label(b)
# 한국은 항상 왼쪽으로 표기(프론트 화면 규칙과 동일). # 한국은 항상 왼쪽으로 표기(프론트 화면 규칙과 동일).
if b == "KOR" and a != "KOR": if b == "KOR" and a != "KOR":
la, lb = lb, la la, lb = lb, la
league_ko = {"kbo": "KBO", "mlb": "MLB", "mls": "MLS"}.get(m.league if m else "", "")
if la and lb: if la and lb:
title = f"TriplePick 2026 — {la} vs {lb} AI 승부예측" tag = f"{league_ko} " if league_ko else ""
title = f"TriplePick — {tag}{la} vs {lb} AI 승부예측"
else: else:
title = "TriplePick 2026 — AI 2026 글로벌 축구 축전 승부예측" title = "TriplePick — AI 스포츠 승부예측 (월드컵·KBO·MLB·MLS)"
desc = "AI 셋이 매 경기를 서로 다르게 예측합니다. 당신의 픽을 찍고 AI와 겨뤄보세요." desc = (
"GPT·Claude·Gemini 3대 AI가 이 경기를 서로 다르게 예측합니다. "
"당신의 픽을 찍고 AI와 겨뤄보세요."
)
origin = settings.public_origin.rstrip("/") origin = settings.public_origin.rstrip("/")
page_url = f"{origin}/match/{html.escape(match_id)}" page_url = f"{origin}/match/{html.escape(match_id)}"
img_url = f"{origin}{image}" # ?v= 캐시버스터: 메신저가 과거 실패/구버전 썸네일을 캐시한 경우 재수집 유도
img_url = f"{origin}{image}?v=2"
t = html.escape(title) t = html.escape(title)
d = html.escape(desc) d = html.escape(desc)
# 기본 썸네일만 규격이 1200x630 으로 확정 → width/height 명시. # 기본 썸네일만 규격이 1200x630 으로 확정 → width/height 명시.

View File

@ -28,8 +28,8 @@
content="GPT·Claude·Gemini 3대 AI가 월드컵·KBO·MLB·MLS 매 경기를 서로 다르게 예측합니다. 당신의 픽을 찍고 AI와 겨뤄보세요. 무료 참여." content="GPT·Claude·Gemini 3대 AI가 월드컵·KBO·MLB·MLS 매 경기를 서로 다르게 예측합니다. 당신의 픽을 찍고 AI와 겨뤄보세요. 무료 참여."
/> />
<meta property="og:url" content="https://triplepick.o2o.kr/" /> <meta property="og:url" content="https://triplepick.o2o.kr/" />
<meta property="og:image" content="https://triplepick.o2o.kr/assets/bi/og-image.png" /> <meta property="og:image" content="https://triplepick.o2o.kr/assets/bi/og-image.png?v=2" />
<meta property="og:image:secure_url" content="https://triplepick.o2o.kr/assets/bi/og-image.png" /> <meta property="og:image:secure_url" content="https://triplepick.o2o.kr/assets/bi/og-image.png?v=2" />
<meta property="og:image:type" content="image/png" /> <meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" /> <meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" /> <meta property="og:image:height" content="630" />
@ -42,7 +42,7 @@
name="twitter:description" name="twitter:description"
content="GPT·Claude·Gemini 3대 AI가 월드컵·KBO·MLB·MLS 매 경기를 예측합니다. 당신의 픽을 찍고 AI와 겨뤄보세요." content="GPT·Claude·Gemini 3대 AI가 월드컵·KBO·MLB·MLS 매 경기를 예측합니다. 당신의 픽을 찍고 AI와 겨뤄보세요."
/> />
<meta name="twitter:image" content="https://triplepick.o2o.kr/assets/bi/og-image.png" /> <meta name="twitter:image" content="https://triplepick.o2o.kr/assets/bi/og-image.png?v=2" />
<!-- 검색엔진 소유확인 (verification) --> <!-- 검색엔진 소유확인 (verification) -->
<meta name="google-site-verification" content="ka2LWpjjrTMayrSJ4_LYowl3w1rt6-RSeaT24xvmUiQ" /> <meta name="google-site-verification" content="ka2LWpjjrTMayrSJ4_LYowl3w1rt6-RSeaT24xvmUiQ" />