pouluo commited on
Commit
d4064f9
·
1 Parent(s): 437ea55

feat: dynamically extract gemini_bl from homepage on startup

Browse files
Files changed (1) hide show
  1. gemini_web2api.py +72 -0
gemini_web2api.py CHANGED
@@ -298,6 +298,55 @@ class GeminiHTTPClient:
298
  else:
299
  log("HTTP transport: urllib (no TLS fingerprinting - less stealthy)")
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  def post(self, url: str, data: bytes, headers: dict, cookies: dict = None) -> str:
302
  """POST request with Chrome fingerprint. Returns response text."""
303
  if self._session:
@@ -942,6 +991,28 @@ def load_config(path: str):
942
  log(f"Config loaded: {path}")
943
 
944
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
945
  def main():
946
  parser = argparse.ArgumentParser(description="Gemini Web to OpenAI API")
947
  parser.add_argument("--port", type=int, default=None)
@@ -968,6 +1039,7 @@ def main():
968
 
969
  # Initialize HTTP client
970
  get_http_client()
 
971
 
972
  class ThreadedServer(ThreadingMixIn, HTTPServer):
973
  daemon_threads = True
 
298
  else:
299
  log("HTTP transport: urllib (no TLS fingerprinting - less stealthy)")
300
 
301
+ def get(self, url: str, headers: dict = None, cookies: dict = None) -> str:
302
+ """GET request with Chrome fingerprint. Returns response text."""
303
+ if self._session:
304
+ return self._get_curl(url, headers, cookies)
305
+ else:
306
+ return self._get_urllib(url, headers, cookies)
307
+
308
+ def _get_curl(self, url: str, headers: dict = None, cookies: dict = None) -> str:
309
+ self._session.cookies.clear()
310
+ proxy = CONFIG.get("proxy")
311
+ proxies = {"http": proxy, "https": proxy} if proxy else None
312
+ resp = self._session.get(
313
+ url,
314
+ headers=dict(headers) if headers else {},
315
+ cookies=cookies or {},
316
+ proxies=proxies,
317
+ allow_redirects=True,
318
+ )
319
+ if resp.status_code != 200:
320
+ raise Exception(f"HTTP {resp.status_code}: {resp.text[:200]}")
321
+ return resp.text
322
+
323
+ def _get_urllib(self, url: str, headers: dict = None, cookies: dict = None) -> str:
324
+ all_headers = dict(headers) if headers else {}
325
+ if cookies:
326
+ cookie_str = "; ".join(f"{k}={v}" for k, v in cookies.items())
327
+ existing = all_headers.get("Cookie", "")
328
+ if existing:
329
+ all_headers["Cookie"] = existing + "; " + cookie_str
330
+ else:
331
+ all_headers["Cookie"] = cookie_str
332
+ req = urllib.request.Request(url, headers=all_headers, method="GET")
333
+ ctx = ssl.create_default_context()
334
+ proxy = CONFIG.get("proxy")
335
+ if proxy:
336
+ opener = urllib.request.build_opener(
337
+ urllib.request.ProxyHandler({"http": proxy, "https": proxy}),
338
+ urllib.request.HTTPSHandler(context=ctx)
339
+ )
340
+ urllib.request.install_opener(opener)
341
+ else:
342
+ opener = urllib.request.build_opener(urllib.request.HTTPSHandler(context=ctx))
343
+ urllib.request.install_opener(opener)
344
+ try:
345
+ with urllib.request.urlopen(req, timeout=CONFIG["request_timeout_sec"]) as resp:
346
+ return resp.read().decode("utf-8")
347
+ except urllib.error.HTTPError as e:
348
+ raise Exception(f"HTTP {e.code}: {e.read().decode('utf-8')[:200]}")
349
+
350
  def post(self, url: str, data: bytes, headers: dict, cookies: dict = None) -> str:
351
  """POST request with Chrome fingerprint. Returns response text."""
352
  if self._session:
 
991
  log(f"Config loaded: {path}")
992
 
993
 
994
+ def update_gemini_bl():
995
+ """Scrape the gemini.google.com homepage to extract the latest gemini_bl parameter."""
996
+ try:
997
+ log("Fetching latest gemini_bl parameter from gemini.google.com...")
998
+ client = get_http_client()
999
+ headers = build_chrome_headers(method="GET")
1000
+ html = client.get("https://gemini.google.com/app", headers=headers)
1001
+
1002
+ # Look for the bl string in the HTML (usually under cfb2h or SNlM0e)
1003
+ match = re.search(r'"cfb2h":"([^"]+)"', html)
1004
+ if not match:
1005
+ match = re.search(r'"SNlM0e":"([^"]+)"', html)
1006
+
1007
+ if match:
1008
+ CONFIG["gemini_bl"] = match.group(1)
1009
+ log(f"Successfully updated gemini_bl to: {CONFIG['gemini_bl']}")
1010
+ else:
1011
+ log("Warning: Could not extract gemini_bl from homepage. Using fallback.")
1012
+ except Exception as e:
1013
+ log(f"Error fetching gemini_bl: {e}. Using fallback.")
1014
+
1015
+
1016
  def main():
1017
  parser = argparse.ArgumentParser(description="Gemini Web to OpenAI API")
1018
  parser.add_argument("--port", type=int, default=None)
 
1039
 
1040
  # Initialize HTTP client
1041
  get_http_client()
1042
+ update_gemini_bl()
1043
 
1044
  class ThreadedServer(ThreadingMixIn, HTTPServer):
1045
  daemon_threads = True