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:
parent
9b57d56daf
commit
22e2e8c29c
@ -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 명시.
|
||||||
|
|||||||
@ -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" />
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user