From 759f772ca81c4cc5d7783442dcf9668edf424764 Mon Sep 17 00:00:00 2001 From: projectdx Date: Wed, 7 Jan 2026 13:54:41 +0900 Subject: [PATCH] Fix: Resolve gevent-Trio conflict on Mac by using Botasaurus subprocess --- info.yaml | 2 +- lib/botasaurus_ohli24.py | 54 ++++++++++++++++++++++++++++++++++++++++ mod_ohli24.py | 52 +++++++++++++++++++++++++++++--------- 3 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 lib/botasaurus_ohli24.py diff --git a/info.yaml b/info.yaml index c60dfb0..d2872f8 100644 --- a/info.yaml +++ b/info.yaml @@ -1,5 +1,5 @@ title: "애니 다운로더" -version: "0.6.8" +version: "0.6.9" package_name: "anime_downloader" developer: "projectdx" description: "anime downloader" diff --git a/lib/botasaurus_ohli24.py b/lib/botasaurus_ohli24.py new file mode 100644 index 0000000..514db2f --- /dev/null +++ b/lib/botasaurus_ohli24.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +""" +Botasaurus 기반 Ohli24 HTML 페칭 스크립트 +- gevent monkey-patching과 Trio 간의 충돌을 방지하기 위해 별도 프로세스로 실행 +- JSON 출력으로 상위 프로세스(mod_ohli24)와 통신 +""" + +import sys +import json +import time +import traceback + +def fetch_html(url, headers=None, proxy=None): + result = {"success": False, "html": "", "elapsed": 0} + start_time = time.time() + + try: + from botasaurus.request import request as b_request + + @b_request(headers=headers, use_stealth=True, proxy=proxy) + def fetch_url(request, data): + return request.get(data) + + b_resp = fetch_url(url) + elapsed = time.time() - start_time + + if b_resp and len(b_resp) > 10: + result.update({ + "success": True, + "html": b_resp, + "elapsed": round(elapsed, 2) + }) + else: + result["error"] = f"Short response: {len(b_resp) if b_resp else 0} bytes" + result["elapsed"] = round(elapsed, 2) + + except Exception as e: + result["error"] = str(e) + result["traceback"] = traceback.format_exc() + result["elapsed"] = round(time.time() - start_time, 2) + + return result + +if __name__ == "__main__": + if len(sys.argv) < 2: + print(json.dumps({"success": False, "error": "Usage: python botasaurus_ohli24.py [headers_json] [proxy]"})) + sys.exit(1) + + target_url = sys.argv[1] + headers_arg = json.loads(sys.argv[2]) if len(sys.argv) > 2 and sys.argv[2] else None + proxy_arg = sys.argv[3] if len(sys.argv) > 3 and sys.argv[3] else None + + res = fetch_html(target_url, headers_arg, proxy_arg) + print(json.dumps(res, ensure_ascii=False)) diff --git a/mod_ohli24.py b/mod_ohli24.py index a7dcc1b..11a7d59 100644 --- a/mod_ohli24.py +++ b/mod_ohli24.py @@ -1950,20 +1950,48 @@ class LogicOhli24(AnimeModuleBase): # === [Layer 1: Botasaurus @request (빠름 - HTTP Request)] === if not response_data or len(response_data) < 10: if LogicOhli24.ensure_essential_dependencies(): + import platform + is_mac = platform.system() == "Darwin" + try: - logger.debug(f"[Layer1] Trying Botasaurus @request: {url}") - from botasaurus.request import request as b_request - - @b_request(headers=headers, use_stealth=True, proxy=LogicOhli24.get_proxy()) - def fetch_url(request, data): - return request.get(data) - - b_resp = fetch_url(url) - if b_resp and len(b_resp) > 10: - logger.info(f"[Layer1] Botasaurus success, HTML len: {len(b_resp)}") - return b_resp + if is_mac: + # Mac에서는 gevent-Trio 충돌로 인해 서브프로세스로 실행 + logger.debug(f"[Layer1] Trying Botasaurus subprocess (Mac workaround): {url}") + import subprocess + script_path = os.path.join(os.path.dirname(__file__), "lib", "botasaurus_ohli24.py") + + cmd = [sys.executable, script_path, url, json.dumps(headers), LogicOhli24.get_proxy() or ""] + result = subprocess.run( + cmd, + capture_output=True, + text=True, + timeout=timeout + 30 + ) + + if result.returncode == 0 and result.stdout.strip(): + b_result = json.loads(result.stdout.strip()) + if b_result.get("success") and b_result.get("html"): + logger.info(f"[Layer1] Botasaurus(sub) success, HTML len: {len(b_result['html'])}") + return b_result["html"] + else: + logger.warning(f"[Layer1] Botasaurus(sub) failed: {b_result.get('error')}") + else: + logger.warning(f"[Layer1] Botasaurus subprocess error: {result.stderr}") else: - logger.warning(f"[Layer1] Botasaurus short response: {len(b_resp) if b_resp else 0}") + # Linux 등에서는 (monkey-patching 문제가 없다면) 직접 실행 시도 + logger.debug(f"[Layer1] Trying Botasaurus @request (Direct): {url}") + from botasaurus.request import request as b_request + + @b_request(headers=headers, use_stealth=True, proxy=LogicOhli24.get_proxy()) + def fetch_url(request, data): + return request.get(data) + + b_resp = fetch_url(url) + if b_resp and len(b_resp) > 10: + logger.info(f"[Layer1] Botasaurus success, HTML len: {len(b_resp)}") + return b_resp + else: + logger.warning(f"[Layer1] Botasaurus short response: {len(b_resp) if b_resp else 0}") except Exception as e: logger.warning(f"[Layer1] Botasaurus failed: {e}")