diff --git a/plugins/douyin_parser/config.toml b/plugins/douyin_parser/config.toml index 7102377..0065ace 100644 --- a/plugins/douyin_parser/config.toml +++ b/plugins/douyin_parser/config.toml @@ -7,4 +7,17 @@ download_mode = "card" # Http代理设置(用于获取真实链接发送卡片,如果家里有ipv6,可以设置为空) # 格式: http://用户名:密码@代理地址:代理端口 # 例如:http://127.0.0.1:7890 -http_proxy = "" \ No newline at end of file +http_proxy = "" + +# 抖音Cookie(可选,建议配置,提升本地提取命中率与稳定性) +# 说明: +# 1. 可直接粘贴浏览器请求头中的完整 Cookie 字符串; +# 2. 当接口解析失败进入本地后备提取时,会携带该 Cookie。 +cookie = "" + +# 抖音Cookie文件路径(可选) +# 说明: +# 1. 仅用于本地后备提取(yt-dlp); +# 2. 若同时配置 cookie 与 cookie_file,优先使用 cookie_file。 +# 例如:D:/learn/abot/resource/douyin_cookies.txt +cookie_file = "" diff --git a/plugins/douyin_parser/main.py b/plugins/douyin_parser/main.py index fb3b73a..dc3623b 100644 --- a/plugins/douyin_parser/main.py +++ b/plugins/douyin_parser/main.py @@ -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_file(yt-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: