Files
HeXi/hexi/plugins/nonebot_plugin_video_analysis/handlers/douyin.py
T
sansenhoshiandClaude Code a789a44f5d feat(video-analysis): 抖音免浏览器解析链路 + 快手支持 + 小红书加固 + 发送防重复
- 抖音(2026-10-13):删除 SSR + playwright 旧链路(douyin_ssr.py 移除,
  douyin_api.py 精简为下载工具),新增 douyin_web.py(x-tt-argus 网关头 +
  web detail 接口 + 最高码率梯/多 CDN 回退下载)与 douyin_sign.py
  (纯 Python a_bogus 签名,vendor 自 f2(Apache-2.0),依赖 gmssl SM3);
  实测 10/10 成功率、单作品 <1s(旧浏览器链路 5-15s 且随机撞验证码)
- 快手(2026-10-08):kuaishou_content.py 分享页 INIT_STATE 静态解析(无登录态),
  清晰度梯最佳档 + 图集 URL 组装,入口/策略/Web 面板同步接入
- 小红书:按链接来源定国际/国内站优先序、视频 backupUrls 逐候选回退、
  图片 urlDefault→infoList WB_DFT→url 三档回退
- 长视频防重复发送(2026-10-13):媒体发送带 per-call _timeout(默认 300s),
  超时=结果未知不再降级重试;auto/active 两条 handler 互斥
- Web 解析封面抽帧 ffmpeg 加 CREATE_NO_WINDOW(pythonw 下不再弹 cmd 黑窗)
- 依赖:+gmssl;测试:新增 test_douyin_web / test_kuaishou_parse / test_video_cleanup,
  扩充 test_video_policy / test_video_sender_link / test_video_group_file / test_video_media_naming

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-13 17:53:17 +08:00

59 lines
1.9 KiB
Python

"""抖音视频/图文解析编排层
链路(2026-10 起,免浏览器):短链/全链接 → `douyin_web.fetch_douyin_web`
(短链重定向、签名请求 web detail 接口、最高码率/最高画质下载都在该模块内)。
旧链路(iesdouyin SSR 静态解析 + playwright 浏览器拦截)已废弃,
详见 services/fetchers/douyin_web.py 顶部说明。
"""
from pathlib import Path
from typing import Optional, Union
from nonebot import logger
from ..services.fetchers.douyin_web import fetch_douyin_web
from ..utils import get_data_dir, parse_netscape_cookies
from ..policy import Policy
from .sender import PendingMedia, _as_paths
async def parse_douyin(
url: str,
) -> tuple[Optional[str], Optional[Union[Path, list[Path]]], bool]:
"""解析抖音链接(短链 / 全链接),返回 (title, file_paths, is_image_post)"""
try:
cookies_path = get_data_dir() / "cookies.txt"
cookies = parse_netscape_cookies(cookies_path)
return await fetch_douyin_web(url, cookies)
except Exception:
logger.exception(f"获取直链失败 {url}")
return None, None, False
async def process_douyin_res(
title: str,
file_paths: Union[Path, list[Path]],
is_private: bool,
image_post: bool,
policy: Policy | None = None,
platform: str | None = None,
) -> tuple[Optional[PendingMedia], Optional[str]]:
"""下载已完成 → 打包为待发送媒体(不上传、不发送、不清理)
多级发送(temp 本地 → S3 链接 → 回退本地)与群文件上传由
send_pending_media 统一按 policy 处理;platform 用于群文件限定平台。
"""
if not file_paths:
return None, None
return (
PendingMedia(
files=_as_paths(file_paths),
image_post=image_post,
is_private=is_private,
policy=policy,
platform=platform,
title=title,
),
None,
)