refactor(douyin): 三层兜底方案最终版(App Feed+TikHub+apizero),移除GoDownloader,清理硬编码Key
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Check push changed paths (push) Successful in 3s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 35s
CI/CD Pipeline / Build Staging API Image (push) Successful in 41s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Failing after 23s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 2m45s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Failing after 4m47s
CI/CD Pipeline / Staging E2E Tests (push) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Has been skipped
CI/CD Pipeline / Validate - Style (push) Failing after 13m13s
CI/CD Pipeline / Integration Tests (push) Successful in 13m53s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 16m1s
CI/CD Pipeline / Unit Tests (push) Successful in 18m59s
CI/CD Pipeline / Validate - Security (push) Successful in 38m11s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Check push changed paths (push) Successful in 3s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 35s
CI/CD Pipeline / Build Staging API Image (push) Successful in 41s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Failing after 23s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 2m45s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Failing after 4m47s
CI/CD Pipeline / Staging E2E Tests (push) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Has been skipped
CI/CD Pipeline / Validate - Style (push) Failing after 13m13s
CI/CD Pipeline / Integration Tests (push) Successful in 13m53s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 16m1s
CI/CD Pipeline / Unit Tests (push) Successful in 18m59s
CI/CD Pipeline / Validate - Security (push) Successful in 38m11s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
- 移除 P3 GoDownloader/RapidAPI(不再需要) - douyin_resolver.py: P0 App Feed(免费) → P1 TikHub → P2 apizero - API Key 全部从 os.environ 读取,无任何硬编码 - 清理 .env.example 中 RAPIDAPI_KEY 配置项 - scripts_ai.py docstring 更新 - 错误码分阶段(parse/asr/download)保留 - yt-dlp/cookies/ttwid 死代码已在前置提交删除
This commit is contained in:
@@ -205,7 +205,6 @@ DOUBAO_MAX_RETRIES=2
|
||||
POINTS_ENABLED=false
|
||||
|
||||
# ==================== 抖音解析多源轮询 (#1963) ====================
|
||||
# P0 App Feed API(免费,默认启用)→ P1 TikHub → P2 apizero → P3 GoDownloader
|
||||
# 无需配置 Key 也可使用(P0 免费源可用),配置 Key 可增加兜底能力
|
||||
|
||||
# TikHub API Key (https://tikhub.io) — $0.001/次起,注册送$0.05
|
||||
@@ -214,5 +213,3 @@ TIKHUB_API_KEY=
|
||||
# apizero.cn API Key (https://v1.apizero.cn) — 国内抖音解析服务
|
||||
APIZERO_API_KEY=
|
||||
|
||||
# RapidAPI Key (https://rapidapi.com) — 订阅 GoDownloader 免费层(60次/分)
|
||||
RAPIDAPI_KEY=
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
三个 AI 工具接口(均挂载在 /api/v1/scripts 前缀下):
|
||||
- POST /extract-from-douyin 从抖音视频提取文案
|
||||
- 入口自动从分享文本中正则提取 http(s) URL,兼容 "复制链接" 粘贴场景
|
||||
- 多源轮询解析(douyin_resolver):App Feed API → TikHub → apizero → GoDownloader
|
||||
- 多源轮询解析(douyin_resolver):App Feed API → TikHub → apizero
|
||||
- 拿到 MP4 直链后优先走火山 MediaKit ASR,失败回退下载+本地 ASR
|
||||
- ASR 空结果时使用 Feed desc 兜底,图文视频直接返回 desc
|
||||
- 所有源均失败时返回具体错误信息(不暴露内部细节)
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
P0: App Feed API 直连(零成本,不用 API Key,当前最稳定)
|
||||
P1: TikHub API(付费 $0.001/次起,稳定)
|
||||
P2: apizero.cn 极数本源(按量付费,国内延迟低)
|
||||
P3: GoDownloader / RapidAPI(免费层 60 次/分兜底)
|
||||
|
||||
任一源成功即返回 MP4 直链 + 标题/文案;所有源均失败时返回 None。
|
||||
每个解析源独立超时(5-8s),总耗时不超过所有源超时之和(实际快速失败时远小于此)。
|
||||
每个解析源独立超时(5-10s),总耗时不超过所有源超时之和(实际快速失败时远小于此)。
|
||||
未配置 API Key 的源自动跳过;无任何 Key 时 P0 仍可使用。
|
||||
"""
|
||||
|
||||
@@ -27,13 +26,11 @@ logger = logging.getLogger(__name__)
|
||||
# ── API Keys from env ──────────────────────────────────────────────────
|
||||
TIKHUB_API_KEY = os.environ.get("TIKHUB_API_KEY", "").strip()
|
||||
APIZERO_API_KEY = os.environ.get("APIZERO_API_KEY", "").strip()
|
||||
RAPIDAPI_KEY = os.environ.get("RAPIDAPI_KEY", "").strip()
|
||||
|
||||
# ── Timeouts (seconds) ────────────────────────────────────────────────
|
||||
_TIMEOUT_APP_FEED = 10
|
||||
_TIMEOUT_TIKHUB = 5
|
||||
_TIMEOUT_APIZERO = 5
|
||||
_TIMEOUT_GODOWNLOADER = 8
|
||||
_TIMEOUT_APP_FEED = 12
|
||||
_TIMEOUT_TIKHUB = 6
|
||||
_TIMEOUT_APIZERO = 6
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -184,41 +181,9 @@ def _resolve_apizero(url: str, api_key: str, timeout: int = _TIMEOUT_APIZERO) ->
|
||||
return None
|
||||
|
||||
|
||||
# ── Provider P3: GoDownloader (RapidAPI) ──────────────────────────────
|
||||
def _resolve_godownloader(url: str, api_key: str, timeout: int = _TIMEOUT_GODOWNLOADER) -> Optional[ResolveResult]:
|
||||
"""GoDownloader via RapidAPI"""
|
||||
if not api_key:
|
||||
return None
|
||||
headers = {
|
||||
"X-RapidAPI-Key": api_key,
|
||||
"X-RapidAPI-Host": "tiktok-download-video-no-watermark.p.rapidapi.com",
|
||||
}
|
||||
try:
|
||||
with httpx.Client(timeout=timeout, verify=False) as c:
|
||||
r = c.get(
|
||||
"https://tiktok-download-video-no-watermark.p.rapidapi.com/auto",
|
||||
headers=headers,
|
||||
params={"url": url},
|
||||
)
|
||||
data = r.json()
|
||||
video_url = (
|
||||
(data.get("video") or {}).get("url")
|
||||
or data.get("video_no_watermark")
|
||||
or data.get("nwm_video_url")
|
||||
or ""
|
||||
)
|
||||
desc = data.get("title", "") or data.get("desc", "")
|
||||
if not video_url:
|
||||
return None
|
||||
return ResolveResult(video_url=video_url, desc=desc, source="godownloader")
|
||||
except Exception as exc:
|
||||
logger.warning("GoDownloader 解析失败: %s", exc)
|
||||
return None
|
||||
|
||||
|
||||
# ── Main API ──────────────────────────────────────────────────────────
|
||||
def resolve_douyin_video(page_url: str) -> Optional[ResolveResult]:
|
||||
"""按 P0→P1→P2→P3 顺序轮询解析抖音视频。
|
||||
"""按 P0→P1→P2 顺序轮询解析抖音视频。
|
||||
|
||||
Args:
|
||||
page_url: 抖音 URL 或含 URL 的分享文本。
|
||||
@@ -234,7 +199,6 @@ def resolve_douyin_video(page_url: str) -> Optional[ResolveResult]:
|
||||
("app_feed", lambda: _resolve_app_feed(url)),
|
||||
("tikhub", lambda: _resolve_tikhub(url, TIKHUB_API_KEY)),
|
||||
("apizero", lambda: _resolve_apizero(url, APIZERO_API_KEY)),
|
||||
("godownloader", lambda: _resolve_godownloader(url, RAPIDAPI_KEY)),
|
||||
]
|
||||
|
||||
enabled_count = 0
|
||||
@@ -243,8 +207,6 @@ def resolve_douyin_video(page_url: str) -> Optional[ResolveResult]:
|
||||
continue
|
||||
if name == "apizero" and not APIZERO_API_KEY:
|
||||
continue
|
||||
if name == "godownloader" and not RAPIDAPI_KEY:
|
||||
continue
|
||||
enabled_count += 1
|
||||
t0 = time.time()
|
||||
try:
|
||||
@@ -278,6 +240,4 @@ def available_providers() -> list[str]:
|
||||
provs.append("tikhub")
|
||||
if APIZERO_API_KEY:
|
||||
provs.append("apizero")
|
||||
if RAPIDAPI_KEY:
|
||||
provs.append("godownloader")
|
||||
return provs
|
||||
|
||||
Reference in New Issue
Block a user