M-hv1 commited on
Commit
e957604
ยท
verified ยท
1 Parent(s): 9f6b209

Update browser_pool.py

Browse files
Files changed (1) hide show
  1. browser_pool.py +17 -27
browser_pool.py CHANGED
@@ -1,7 +1,7 @@
1
  """
2
  โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
3
  โ•‘ Browser Pool Manager for Titan Downloader โ•‘
4
- โ•‘ Uses Playwright to provide fresh browser contexts โ•‘
5
  โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
6
  """
7
  import asyncio
@@ -16,17 +16,15 @@ from playwright.async_api import async_playwright, Browser, BrowserContext, Play
16
 
17
  log = logging.getLogger("titan-dl.browser")
18
 
19
- # ุฅุนุฏุงุฏุงุช ุงู„ู…ุชุตูุญ
20
  HEADLESS = os.environ.get("BROWSER_HEADLESS", "true").lower() == "true"
21
- PROXY_SERVER = os.environ.get("PROXY_SERVER") # e.g., "http://user:pass@proxy.com:8080"
22
  USER_AGENT = (
23
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
24
  "AppleWebKit/537.36 (KHTML, like Gecko) "
25
- "Chrome/124.0.0.0 Safari/537.36"
26
  )
27
 
28
  class BrowserPool:
29
- """ุชุฌู…ุน ู…ุชุตูุญุงุช Chromium ู„ุฅุนุงุฏุฉ ุงู„ุงุณุชุฎุฏุงู…."""
30
  _playwright: Optional[Playwright] = None
31
  _browsers: List[Browser] = []
32
  _lock = asyncio.Lock()
@@ -45,7 +43,6 @@ class BrowserPool:
45
 
46
  @classmethod
47
  async def _launch_browser(cls) -> Browser:
48
- """ุฅุทู„ุงู‚ ู…ุชุตูุญ Chromium ุฌุฏูŠุฏ."""
49
  launch_args = [
50
  "--no-sandbox",
51
  "--disable-setuid-sandbox",
@@ -66,10 +63,8 @@ class BrowserPool:
66
 
67
  @classmethod
68
  async def acquire_context(cls) -> BrowserContext:
69
- """ุงุณุชุนุงุฑุฉ ุณูŠุงู‚ ู…ุชุตูุญ (ู…ุน ูƒูˆูƒูŠุฒ ูˆุฌู„ุณุฉ ู…ุณุชู‚ู„ุฉ)."""
70
  async with cls._lock:
71
  if not cls._browsers:
72
- # ุฅุฐุง ู†ูุฏุช ุงู„ู…ุชุตูุญุงุชุŒ ุฃู†ุดุฆ ูˆุงุญุฏู‹ุง ุฌุฏูŠุฏู‹ุง ู…ุคู‚ุชู‹ุง
73
  log.warning("Browser pool exhausted, creating temporary browser.")
74
  browser = await cls._launch_browser()
75
  else:
@@ -81,31 +76,29 @@ class BrowserPool:
81
  viewport={"width": 1920, "height": 1080},
82
  locale="en-US",
83
  timezone_id="America/New_York",
84
- # ู…ุญุงูƒุงุฉ ุฅุนุฏุงุฏุงุช ุฅุถุงููŠุฉ ู„ุชุฌู†ุจ ุงู„ูƒุดู
85
  extra_http_headers={
86
  "Accept-Language": "en-US,en;q=0.9",
 
 
 
87
  },
88
  )
89
- # ุฅุนุงุฏุฉ ุงู„ู…ุชุตูุญ ู„ู„ุชุฌู…ุน ุจุนุฏ ุงู„ุงุณุชุฎุฏุงู… (ุณูŠุชู… ุชุญุฑูŠุฑู‡ ู„ุงุญู‚ุงู‹)
90
  context.on("close", lambda: asyncio.create_task(cls._return_browser(browser)))
91
  return context
92
  except Exception:
93
- # ุฅุฐุง ูุดู„ ุฅู†ุดุงุก ุงู„ุณูŠุงู‚ุŒ ู†ุนูŠุฏ ุงู„ู…ุชุตูุญ ู„ู„ุชุฌู…ุน
94
  await cls._return_browser(browser)
95
  raise
96
 
97
  @classmethod
98
  async def _return_browser(cls, browser: Browser):
99
- """ุฅุนุงุฏุฉ ู…ุชุตูุญ ุฅู„ู‰ ุงู„ุชุฌู…ุน (ุฃูˆ ุฅุบู„ุงู‚ู‡ ุฅุฐุง ูƒุงู† ู…ู…ุชู„ุฆู‹ุง)."""
100
  async with cls._lock:
101
- if len(cls._browsers) < 4: # ุงู„ุญุฏ ุงู„ุฃู‚ุตู‰ ูƒู…ุง ููŠ pool_size
102
  cls._browsers.append(browser)
103
  else:
104
  await browser.close()
105
 
106
  @classmethod
107
  async def close(cls):
108
- """ุฅุบู„ุงู‚ ุฌู…ูŠุน ุงู„ู…ุชุตูุญุงุช ูˆุฅู†ู‡ุงุก Playwright."""
109
  async with cls._lock:
110
  for browser in cls._browsers:
111
  await browser.close()
@@ -117,20 +110,20 @@ class BrowserPool:
117
 
118
  async def extract_with_browser(url: str) -> dict:
119
  """
120
- ุงุณุชุฎุฑุงุฌ ู…ุนู„ูˆู…ุงุช ุงู„ููŠุฏูŠูˆ ุจุงุณุชุฎุฏุงู… ู…ุชุตูุญ ุญู‚ูŠู‚ูŠ (Playwright) ู„ู„ุญุตูˆู„ ุนู„ู‰ ูƒูˆูƒูŠุฒ ูˆุฌู„ุณุฉ ุญูŠุฉุŒ
121
- ุซู… ุชู…ุฑูŠุฑู‡ุง ุฅู„ู‰ yt-dlp.
122
  """
123
  context = await BrowserPool.acquire_context()
124
  try:
125
  page = await context.new_page()
126
 
127
- # ุฒูŠุงุฑุฉ ุงู„ู…ูˆู‚ุน ุงู„ู…ุณุชู‡ุฏู ู„ุชูˆู„ูŠุฏ ุงู„ูƒูˆูƒูŠุฒ ุงู„ู„ุงุฒู…ุฉ
128
- domain = urllib.parse.urlparse(url).netloc
129
- log.info(f"๐ŸŒ Navigating to {domain} with browser...")
130
- await page.goto(f"https://{domain}", wait_until="domcontentloaded")
131
- await asyncio.sleep(2) # ุงู†ุชุธุงุฑ ุชุญู…ูŠู„ ุจุนุถ ุงู„ุณูƒุฑุจุชุงุช
132
 
133
- # ุงุณุชุฎุฑุงุฌ ุงู„ูƒูˆูƒูŠุฒ ุจุตูŠุบุฉ Netscape
134
  cookies = await context.cookies()
135
  netscape_cookies = _cookies_to_netscape(cookies)
136
 
@@ -140,16 +133,14 @@ async def extract_with_browser(url: str) -> dict:
140
  cookie_file = f.name
141
 
142
  try:
143
- # ุงุณุชุฎุฏุงู… yt-dlp ู…ุน ู…ู„ู ุงู„ูƒูˆูƒูŠุฒ
144
- from main import YDL_OPTS_BASE, _extract_info_ytdlp # ุงุณุชูŠุฑุงุฏ ู…ู† ุงู„ู…ู„ู ุงู„ุฑุฆูŠุณูŠ
145
 
146
  opts = YDL_OPTS_BASE.copy()
147
  opts["cookiefile"] = cookie_file
148
- # ูŠู…ูƒู† ุฅุถุงูุฉ ูˆูƒูŠู„ ุฅุฐุง ุฃุฑุฏุช (ู†ูุณ ูˆูƒูŠู„ ุงู„ู…ุชุตูุญ)
149
  if PROXY_SERVER:
150
  opts["proxy"] = PROXY_SERVER
151
 
152
- log.info("๐Ÿ”ง Running yt-dlp with browser cookies...")
153
  data = _extract_info_ytdlp(url, ydl_opts=opts)
154
  return data
155
  finally:
@@ -160,7 +151,6 @@ async def extract_with_browser(url: str) -> dict:
160
 
161
 
162
  def _cookies_to_netscape(cookies: list) -> str:
163
- """ุชุญูˆูŠู„ ู‚ุงุฆู…ุฉ ูƒูˆูƒูŠุฒ Playwright ุฅู„ู‰ ุชู†ุณูŠู‚ Netscape."""
164
  lines = ["# Netscape HTTP Cookie File", ""]
165
  for c in cookies:
166
  domain = c.get("domain", "")
 
1
  """
2
  โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
3
  โ•‘ Browser Pool Manager for Titan Downloader โ•‘
4
+ โ•‘ Enhanced: visits target URL, realistic headers โ•‘
5
  โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
6
  """
7
  import asyncio
 
16
 
17
  log = logging.getLogger("titan-dl.browser")
18
 
 
19
  HEADLESS = os.environ.get("BROWSER_HEADLESS", "true").lower() == "true"
20
+ PROXY_SERVER = os.environ.get("PROXY_SERVER")
21
  USER_AGENT = (
22
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
23
  "AppleWebKit/537.36 (KHTML, like Gecko) "
24
+ "Chrome/131.0.0.0 Safari/537.36"
25
  )
26
 
27
  class BrowserPool:
 
28
  _playwright: Optional[Playwright] = None
29
  _browsers: List[Browser] = []
30
  _lock = asyncio.Lock()
 
43
 
44
  @classmethod
45
  async def _launch_browser(cls) -> Browser:
 
46
  launch_args = [
47
  "--no-sandbox",
48
  "--disable-setuid-sandbox",
 
63
 
64
  @classmethod
65
  async def acquire_context(cls) -> BrowserContext:
 
66
  async with cls._lock:
67
  if not cls._browsers:
 
68
  log.warning("Browser pool exhausted, creating temporary browser.")
69
  browser = await cls._launch_browser()
70
  else:
 
76
  viewport={"width": 1920, "height": 1080},
77
  locale="en-US",
78
  timezone_id="America/New_York",
 
79
  extra_http_headers={
80
  "Accept-Language": "en-US,en;q=0.9",
81
+ "sec-ch-ua": '"Chromium";v="131", "Not_A Brand";v="24"',
82
+ "sec-ch-ua-mobile": "?0",
83
+ "sec-ch-ua-platform": '"Windows"',
84
  },
85
  )
 
86
  context.on("close", lambda: asyncio.create_task(cls._return_browser(browser)))
87
  return context
88
  except Exception:
 
89
  await cls._return_browser(browser)
90
  raise
91
 
92
  @classmethod
93
  async def _return_browser(cls, browser: Browser):
 
94
  async with cls._lock:
95
+ if len(cls._browsers) < 4:
96
  cls._browsers.append(browser)
97
  else:
98
  await browser.close()
99
 
100
  @classmethod
101
  async def close(cls):
 
102
  async with cls._lock:
103
  for browser in cls._browsers:
104
  await browser.close()
 
110
 
111
  async def extract_with_browser(url: str) -> dict:
112
  """
113
+ ุงุณุชุฎุฑุงุฌ ู…ุนู„ูˆู…ุงุช ุงู„ููŠุฏูŠูˆ ุจุงุณุชุฎุฏุงู… ู…ุชุตูุญ ุญู‚ูŠู‚ูŠ.
114
+ ูŠู‚ูˆู… ุจุฒูŠุงุฑุฉ ุตูุญุฉ ุงู„ููŠุฏูŠูˆ ู†ูุณู‡ุง ู„ุชูˆู„ูŠุฏ ุงู„ูƒูˆูƒูŠุฒ ุงู„ู…ู†ุงุณุจุฉ.
115
  """
116
  context = await BrowserPool.acquire_context()
117
  try:
118
  page = await context.new_page()
119
 
120
+ # ุฒูŠุงุฑุฉ ุตูุญุฉ ุงู„ููŠุฏูŠูˆ ู…ุจุงุดุฑุฉ (ูˆู„ูŠุณ ูู‚ุท ุงู„ุตูุญุฉ ุงู„ุฑุฆูŠุณูŠุฉ)
121
+ log.info(f"๐ŸŒ Visiting video URL with browser: {url[:60]}...")
122
+ await page.goto(url, wait_until="domcontentloaded", timeout=30000)
123
+ # ุงู†ุชุธุฑ ู‚ู„ูŠู„ุงู‹ ู„ุชุญู…ูŠู„ ุจุนุถ ุงู„ุนู†ุงุตุฑ ูˆุชู†ููŠุฐ ุงู„ุณูƒุฑูŠุจุชุงุช
124
+ await asyncio.sleep(3)
125
 
126
+ # ุงุณุชุฎุฑุงุฌ ุงู„ูƒูˆูƒูŠุฒ
127
  cookies = await context.cookies()
128
  netscape_cookies = _cookies_to_netscape(cookies)
129
 
 
133
  cookie_file = f.name
134
 
135
  try:
136
+ from main import YDL_OPTS_BASE, _extract_info_ytdlp
 
137
 
138
  opts = YDL_OPTS_BASE.copy()
139
  opts["cookiefile"] = cookie_file
 
140
  if PROXY_SERVER:
141
  opts["proxy"] = PROXY_SERVER
142
 
143
+ log.info("๐Ÿ”ง Running yt-dlp with fresh browser cookies...")
144
  data = _extract_info_ytdlp(url, ydl_opts=opts)
145
  return data
146
  finally:
 
151
 
152
 
153
  def _cookies_to_netscape(cookies: list) -> str:
 
154
  lines = ["# Netscape HTTP Cookie File", ""]
155
  for c in cookies:
156
  domain = c.get("domain", "")