style: auto-format with black + isort + ruff + prettier [skip ci-format-check]
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 / 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 / Check push changed paths (push) Successful in 2s
CI/CD Pipeline / Frontend Lint (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 1m53s
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) Successful in 13s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 2m31s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 52s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m35s
CI/CD Pipeline / Integration Tests (push) Successful in 5m3s
CI/CD Pipeline / Validate - Style (push) Failing after 5m41s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m44s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m4s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 3m15s
CI/CD Pipeline / Validate - Security (push) Successful in 14m0s
CI/CD Pipeline / Unit Tests (push) Failing after 19m49s
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

This commit is contained in:
CI Bot
2026-09-17 08:48:26 +00:00
parent f2bc951903
commit 54a3c50035
2 changed files with 22 additions and 9 deletions
+5 -4
View File
@@ -356,7 +356,7 @@ def _fetch_ttwid():
# 方式一:直接调 ttwid 注册接口
try:
with httpx.Client(timeout=8, follow_redirects=True, verify=False) as http:
r = http.post(
http.post(
"https://ttwid.bytedance.com/ttwid/union/register/",
json={
"region": "cn",
@@ -769,7 +769,7 @@ def _ytdlp_download_and_local_asr(page_url, temp_dir, cookiefile=None):
cookie_files_to_try.append(cookiefile)
# 2. 合成 cookie 重试(复用 _ytdlp_extract 的 cookie 生成逻辑,8次重试)
import secrets, time as _time
import time as _time
ttwid = _fetch_ttwid()
for i in range(8):
if i % 3 == 0:
@@ -945,9 +945,10 @@ def _html_scrape_direct_url(page_url, timeout=15):
@router.get("/douyin/__debug_diag")
def douyin_diag():
"""[Staging only] 容器内网络/yt-dlp诊断"""
import httpx as _httpx
import time as _t
import tempfile as _tf
import time as _t
import httpx as _httpx
import yt_dlp as _ytdlp
results = {}
+17 -5
View File
@@ -4,6 +4,7 @@
接口直接返回 aweme_list 包含视频元信息和 play_addr 无水印直链。
此接口不需要任何签名算法、不需要 cookies、不需要特殊 TLS 指纹,稳定性 >95%。
"""
from __future__ import annotations
import logging
@@ -39,7 +40,9 @@ def _extract_aweme_id(url: str) -> Optional[str]:
return None
def fetch_douyin_video_url(page_url: str, timeout: int = 15, max_retries: int = 3) -> Tuple[Optional[str], Optional[str]]:
def fetch_douyin_video_url(
page_url: str, timeout: int = 15, max_retries: int = 3
) -> Tuple[Optional[str], Optional[str]]:
"""通过抖音 App Feed API 获取视频无水印直链和文案。
Args:
@@ -90,7 +93,9 @@ def fetch_douyin_video_url(page_url: str, timeout: int = 15, max_retries: int =
continue
if len(resp.text) < 100:
logger.warning("Feed API 第%d次: 返回内容过短 len=%d body=%s", attempt + 1, len(resp.text), resp.text[:100])
logger.warning(
"Feed API 第%d次: 返回内容过短 len=%d body=%s", attempt + 1, len(resp.text), resp.text[:100]
)
time.sleep(0.5 * (attempt + 1))
continue
@@ -101,7 +106,9 @@ def fetch_douyin_video_url(page_url: str, timeout: int = 15, max_retries: int =
status_msg = data.get("status_msg", "")
logger.warning(
"Feed API 第%d次: aweme_list 为空 status_code=%s msg=%s",
attempt + 1, status_code, status_msg,
attempt + 1,
status_code,
status_msg,
)
time.sleep(0.5 * (attempt + 1))
continue
@@ -131,7 +138,11 @@ def fetch_douyin_video_url(page_url: str, timeout: int = 15, max_retries: int =
duration = video.get("duration", 0) / 1000 if video.get("duration") else 0
logger.info(
"抖音 Feed API 成功(第%d次): aweme_id=%s play_len=%d desc_len=%d dur=%.1f",
attempt + 1, aweme_id, len(play_url), len(desc), duration,
attempt + 1,
aweme_id,
len(play_url),
len(desc),
duration,
)
return play_url, desc
@@ -148,11 +159,12 @@ def fetch_douyin_video_url(page_url: str, timeout: int = 15, max_retries: int =
if __name__ == "__main__":
import sys
logging.basicConfig(level=logging.INFO)
test_url = sys.argv[1] if len(sys.argv) > 1 else "https://www.douyin.com/video/7661819662322649065"
url, desc = fetch_douyin_video_url(test_url)
if url:
print(f"\n✅ SUCCESS!")
print("\n✅ SUCCESS!")
print(f"desc: {desc}")
print(f"play_url: {url[:200]}")
else: