抖音解析新增Cookie配置并接入本地后备提取链路

变更项:

- 配置文件新增 cookie 与 cookie_file 两个参数,支持账号态提取

- 解析请求与媒资下载统一接入请求头构建,按配置自动注入 Cookie

- yt-dlp Python/命令行两种后备提取方式均支持 Cookie 注入

- Cookie 注入策略为 cookie_file 优先、cookie 次之,提升受限场景下无水印链接提取成功率
This commit is contained in:
liuwei
2026-04-23 15:34:12 +08:00
parent 86efbb337c
commit bb8894097e
2 changed files with 73 additions and 5 deletions

View File

@@ -91,6 +91,12 @@ class DouyinParserPlugin(MessagePluginInterface):
douyin_config = self._config.get("Douyin", {})
self.enable = douyin_config.get("enable", True)
self.http_proxy = douyin_config.get("http_proxy", "")
# Cookie 配置说明:
# 1) cookie: 直接粘贴请求头 Cookie 字符串;
# 2) cookie_file: Netscape 格式 cookies 文件路径;
# 3) 当二者同时存在时,后备提取优先 cookie_file兼容性更好
self.cookie = douyin_config.get("cookie", "") or ""
self.cookie_file = douyin_config.get("cookie_file", "") or ""
self.download_mode = douyin_config.get("download_mode", "card") # card或file
self.LOG.debug(f"[{self.name}] 插件初始化完成,代理设置: {self.http_proxy}")
@@ -261,10 +267,30 @@ class DouyinParserPlugin(MessagePluginInterface):
return {"http": self.http_proxy, "https": self.http_proxy}
return None
def _build_request_headers(self) -> Dict[str, str]:
"""
构建通用请求头。
设计说明:
- User-Agent 保持常规浏览器标识,降低被目标站点直接拒绝的概率;
- Cookie 在有配置时注入到请求头,提升受限资源的提取成功率。
"""
headers = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/124.0.0.0 Safari/537.36"
)
}
if self.cookie:
headers["Cookie"] = self.cookie
return headers
def _parse_from_internal_api(self, clean_url: str) -> Optional[Dict[str, Any]]:
try:
endpoint = "http://192.168.2.32:8999/api/hybrid/video_data"
headers = {"accept": "application/json"}
headers = self._build_request_headers()
headers["accept"] = "application/json"
params = {"url": clean_url, "minimal": "false"}
response = requests.get(endpoint, headers=headers, params=params, timeout=10, proxies=self._build_proxies())
if response.status_code != 200:
@@ -325,7 +351,13 @@ class DouyinParserPlugin(MessagePluginInterface):
try:
pay_api_url = "https://api.pearktrue.cn/api/video/api.php"
params = {"url": clean_url, "key": "f56c1fed0c6e64e7"}
response = requests.post(pay_api_url, params=params, timeout=10, proxies=self._build_proxies())
response = requests.post(
pay_api_url,
params=params,
headers=self._build_request_headers(),
timeout=10,
proxies=self._build_proxies(),
)
if response.status_code != 200:
return None
data = response.json() or {}
@@ -391,7 +423,13 @@ class DouyinParserPlugin(MessagePluginInterface):
"""
try:
# 发送GET请求启用流式传输
response = requests.get(url, stream=True)
response = requests.get(
url,
stream=True,
headers=self._build_request_headers(),
proxies=self._build_proxies(),
timeout=30,
)
# 检查请求是否成功
response.raise_for_status() # 如果状态码不是200将抛出异常
@@ -423,7 +461,12 @@ class DouyinParserPlugin(MessagePluginInterface):
def _download_image_bytes(self, url: str) -> Optional[bytes]:
try:
resp = requests.get(url, timeout=15, proxies=self._build_proxies())
resp = requests.get(
url,
headers=self._build_request_headers(),
timeout=15,
proxies=self._build_proxies(),
)
if resp.status_code == 200:
return resp.content
return None
@@ -540,6 +583,13 @@ class DouyinParserPlugin(MessagePluginInterface):
"proxy": self.http_proxy or None,
"nocheckcertificate": True,
}
# Cookie 注入策略:
# - 优先使用 cookie_fileyt-dlp 官方支持的 cookies 文件,兼容性更高);
# - 否则回退到手工 Cookie 请求头。
if self.cookie_file and os.path.exists(self.cookie_file):
ydl_opts["cookiefile"] = self.cookie_file
elif self.cookie:
ydl_opts["http_headers"] = {"Cookie": self.cookie}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(clean_url, download=False)
if isinstance(info, dict):
@@ -559,6 +609,11 @@ class DouyinParserPlugin(MessagePluginInterface):
cmd = [yt_dlp_bin, "-J", "--no-warnings", "--skip-download", clean_url]
if self.http_proxy:
cmd.extend(["--proxy", self.http_proxy])
# 命令行模式下同样注入 Cookie确保与 Python 模式行为一致。
if self.cookie_file and os.path.exists(self.cookie_file):
cmd.extend(["--cookies", self.cookie_file])
elif self.cookie:
cmd.extend(["--add-header", f"Cookie: {self.cookie}"])
result = subprocess.run(cmd, capture_output=True, text=True, timeout=25)
if result.returncode != 0: