This commit is contained in:
2026-01-25 05:40:08 +08:00
parent af161cca4f
commit 32e926c4af
9 changed files with 1495 additions and 13 deletions

2
.gitignore vendored
View File

@@ -34,3 +34,5 @@ nul
.claude/settings.local.json .claude/settings.local.json
autogptplus_drission.py autogptplus_drission.py
autogptplus_drission_oai.py
accounts.json

624
api_register.py Normal file
View File

@@ -0,0 +1,624 @@
"""
ChatGPT API 注册模块 (协议模式)
- 使用 curl_cffi 通过 API 快速完成注册
- 支持 Cookie 注入到浏览器完成支付
"""
import time
import random
import re
import uuid
from urllib.parse import unquote
try:
from curl_cffi import requests as curl_requests
CURL_CFFI_AVAILABLE = True
except ImportError:
CURL_CFFI_AVAILABLE = False
curl_requests = None
import requests
def log_status(step, message):
"""日志输出"""
timestamp = time.strftime("%H:%M:%S")
print(f"[{timestamp}] [{step}] {message}")
def log_progress(message):
"""进度输出"""
print(f" -> {message}")
def request_with_retry(func, *args, max_retries=3, **kwargs):
"""带重试的请求"""
for i in range(max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
if i == max_retries - 1:
raise e
time.sleep(1)
class ChatGPTAPIRegister:
"""ChatGPT API 注册类 (协议模式)"""
def __init__(self, proxy=None):
"""初始化
Args:
proxy: 代理地址,如 "http://127.0.0.1:7890"
"""
if not CURL_CFFI_AVAILABLE:
raise ImportError("协议模式需要安装 curl_cffi: pip install curl_cffi")
self.session = curl_requests.Session(
impersonate="edge",
verify=False,
proxies={"http": proxy, "https": proxy} if proxy else {}
)
self.auth_session_logging_id = str(uuid.uuid4())
self.oai_did = ""
self.csrf_token = ""
self.authorize_url = ""
self.access_token = ""
def init_session(self) -> bool:
"""初始化会话,获取必要的 cookies 和 tokens"""
try:
resp = request_with_retry(self.session.get, "https://chatgpt.com")
if resp.status_code != 200:
log_progress(f"[X] 初始化失败: HTTP {resp.status_code}")
return False
self.oai_did = self.session.cookies.get("oai-did")
csrf_cookie = self.session.cookies.get("__Host-next-auth.csrf-token")
if csrf_cookie:
self.csrf_token = unquote(csrf_cookie).split("|")[0]
else:
log_progress("[X] 未获取到 CSRF token")
return False
# 访问登录页面
request_with_retry(
self.session.get,
f"https://chatgpt.com/auth/login?openaicom-did={self.oai_did}"
)
return True
except Exception as e:
log_progress(f"[X] 初始化异常: {e}")
return False
def get_authorize_url(self, email: str) -> bool:
"""获取授权 URL"""
try:
url = f"https://chatgpt.com/api/auth/signin/openai?prompt=login&ext-oai-did={self.oai_did}&auth_session_logging_id={self.auth_session_logging_id}&screen_hint=login_or_signup&login_hint={email}"
payload = {
"callbackUrl": "https://chatgpt.com/",
"csrfToken": self.csrf_token,
"json": "true"
}
resp = request_with_retry(
self.session.post, url, data=payload,
headers={"Origin": "https://chatgpt.com"}
)
data = resp.json()
if data.get("url") and "auth.openai.com" in data["url"]:
self.authorize_url = data["url"]
return True
log_progress(f"[X] 授权 URL 无效: {data}")
return False
except Exception as e:
log_progress(f"[X] 获取授权 URL 异常: {e}")
return False
def start_authorize(self) -> bool:
"""启动授权流程"""
try:
resp = request_with_retry(
self.session.get, self.authorize_url, allow_redirects=True
)
return "create-account" in resp.url or "log-in" in resp.url
except Exception as e:
log_progress(f"[X] 启动授权异常: {e}")
return False
def register(self, email: str, password: str) -> bool:
"""注册账户"""
try:
resp = request_with_retry(
self.session.post,
"https://auth.openai.com/api/accounts/user/register",
json={"password": password, "username": email},
headers={
"Content-Type": "application/json",
"Origin": "https://auth.openai.com"
}
)
if resp.status_code == 200:
return True
log_progress(f"[X] 注册失败: {resp.status_code} - {resp.text[:200]}")
return False
except Exception as e:
log_progress(f"[X] 注册异常: {e}")
return False
def send_verification_email(self) -> bool:
"""发送验证邮件"""
try:
resp = request_with_retry(
self.session.get,
"https://auth.openai.com/api/accounts/email-otp/send",
allow_redirects=True
)
return resp.status_code == 200
except Exception as e:
log_progress(f"[X] 发送验证邮件异常: {e}")
return False
def validate_otp(self, otp_code: str) -> bool:
"""验证 OTP 码"""
try:
resp = request_with_retry(
self.session.post,
"https://auth.openai.com/api/accounts/email-otp/validate",
json={"code": otp_code},
headers={
"Content-Type": "application/json",
"Origin": "https://auth.openai.com"
}
)
if resp.status_code == 200:
return True
log_progress(f"[X] OTP 验证失败: {resp.status_code} - {resp.text[:200]}")
return False
except Exception as e:
log_progress(f"[X] OTP 验证异常: {e}")
return False
def create_account(self, name: str, birthdate: str) -> bool:
"""创建账户 (填写姓名和生日)
Args:
name: 姓名
birthdate: 生日,格式 "YYYY-MM-DD"
"""
try:
resp = request_with_retry(
self.session.post,
"https://auth.openai.com/api/accounts/create_account",
json={"name": name, "birthdate": birthdate},
headers={
"Content-Type": "application/json",
"Origin": "https://auth.openai.com"
}
)
if resp.status_code != 200:
log_progress(f"[X] 创建账户失败: {resp.status_code} - {resp.text[:200]}")
return False
data = resp.json()
continue_url = data.get("continue_url")
if continue_url:
request_with_retry(self.session.get, continue_url, allow_redirects=True)
return True
except Exception as e:
log_progress(f"[X] 创建账户异常: {e}")
return False
def login(self, email: str, password: str) -> bool:
"""使用密码登录 (复用注册时建立的会话)"""
try:
resp = request_with_retry(
self.session.post,
"https://auth.openai.com/api/accounts/password/verify",
json={"username": email, "password": password},
headers={
"Content-Type": "application/json",
"Origin": "https://auth.openai.com"
}
)
if resp.status_code == 200:
data = resp.json()
continue_url = data.get("continue_url")
if continue_url:
request_with_retry(self.session.get, continue_url, allow_redirects=True)
return True
log_progress(f"[X] 登录失败: {resp.status_code} - {resp.text[:200]}")
return False
except Exception as e:
log_progress(f"[X] 登录异常: {e}")
return False
def get_session_token(self) -> str:
"""获取 access token"""
try:
resp = request_with_retry(self.session.get, "https://chatgpt.com/api/auth/session")
if resp.status_code == 200:
data = resp.json()
token = data.get("accessToken")
if token:
self.access_token = token
return token
log_progress(f"[X] Session 响应无 token: {str(data)[:200]}")
else:
log_progress(f"[X] Session 请求失败: {resp.status_code}")
return ""
except Exception as e:
log_progress(f"[X] 获取 token 异常: {e}")
return ""
def get_checkout_url(self) -> str:
"""通过 API 获取支付页 URL"""
try:
token = self.access_token or self.get_session_token()
if not token:
log_progress("[X] 无法获取 access token")
return ""
payload = {
"plan_name": "chatgptteamplan",
"team_plan_data": {
"workspace_name": "Sepa",
"price_interval": "month",
"seat_quantity": 5
},
"billing_details": {
"country": "DE",
"currency": "EUR"
},
"promo_campaign": {
"promo_campaign_id": "team-1-month-free",
"is_coupon_from_query_param": True
},
"checkout_ui_mode": "redirect"
}
resp = request_with_retry(
self.session.post,
"https://chatgpt.com/backend-api/payments/checkout",
json=payload,
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
"Origin": "https://chatgpt.com"
}
)
if resp.status_code == 200:
data = resp.json()
checkout_url = data.get("url")
if checkout_url:
return checkout_url
log_progress(f"[X] 响应无 URL: {resp.text[:200]}")
else:
log_progress(f"[X] 获取支付页失败: {resp.status_code} - {resp.text[:200]}")
return ""
except Exception as e:
log_progress(f"[X] 获取支付页异常: {e}")
return ""
def get_cookies(self) -> list:
"""获取所有 cookies 用于注入浏览器"""
cookies = []
for cookie in self.session.cookies.jar:
cookies.append({
"name": cookie.name,
"value": cookie.value,
"domain": cookie.domain,
"path": cookie.path or "/",
"secure": cookie.secure,
})
return cookies
def get_verification_code_api(target_email: str, mail_api_base: str, mail_api_token: str, max_retries: int = 90) -> str:
"""通过 API 获取验证码
Args:
target_email: 目标邮箱
mail_api_base: 邮件 API 地址
mail_api_token: 邮件 API Token
max_retries: 最大重试次数
Returns:
str: 验证码,失败返回空字符串
"""
log_status("API监听", "正在监听邮件...")
headers = {"Authorization": mail_api_token, "Content-Type": "application/json"}
start_time = time.time()
for i in range(max_retries):
elapsed = int(time.time() - start_time)
try:
url = f"{mail_api_base}/api/public/emailList"
payload = {"toEmail": target_email, "timeSort": "desc", "size": 20}
resp = requests.post(url, headers=headers, json=payload, timeout=10)
if resp.status_code == 200:
data = resp.json()
if data.get('code') == 200:
mails = data.get('data', [])
if mails:
for mail in mails:
html_body = mail.get('content') or mail.get('text') or str(mail)
code_match = re.search(r'\b(\d{6})\b', html_body)
if code_match:
code = code_match.group(1)
log_status("捕获", f"[OK] 提取到验证码: {code}")
return code
except Exception:
pass
if i % 5 == 0:
print(f" [监听中] 已耗时 {elapsed}秒...")
time.sleep(2)
log_status("超时", "[X] 未能获取验证码")
return ""
def api_register_flow(
email: str,
password: str,
real_name: str,
birthdate: str,
mail_api_base: str,
mail_api_token: str,
proxy: str = None,
progress_callback=None
) -> ChatGPTAPIRegister:
"""执行 API 注册流程
Args:
email: 邮箱
password: 密码
real_name: 姓名
birthdate: 生日 (YYYY-MM-DD)
mail_api_base: 邮件 API 地址
mail_api_token: 邮件 API Token
proxy: 代理地址
progress_callback: 进度回调
Returns:
ChatGPTAPIRegister: 成功返回 reg 对象,失败返回 None
"""
def log_cb(msg):
if progress_callback:
progress_callback(msg)
log_progress(msg)
reg = ChatGPTAPIRegister(proxy=proxy)
try:
log_status("API注册", "初始化会话...")
if not reg.init_session():
log_cb("[X] 初始化失败")
return None
log_cb("[OK] 会话初始化成功")
log_status("API注册", "获取授权 URL...")
if not reg.get_authorize_url(email):
log_cb("[X] 获取授权 URL 失败")
return None
log_cb("[OK] 授权 URL 获取成功")
log_status("API注册", "开始授权流程...")
if not reg.start_authorize():
log_cb("[X] 授权流程启动失败")
return None
log_cb("[OK] 授权流程已启动")
log_status("API注册", "注册账户...")
if not reg.register(email, password):
log_cb("[X] 注册失败")
return None
log_cb("[OK] 账户注册成功")
log_status("API注册", "发送验证邮件...")
if not reg.send_verification_email():
log_cb("[X] 发送验证邮件失败")
return None
log_cb("[OK] 验证邮件已发送")
# 获取验证码
otp_code = get_verification_code_api(email, mail_api_base, mail_api_token)
if not otp_code:
log_cb("[X] 未能获取验证码")
return None
log_status("API注册", f"验证 OTP: {otp_code}")
if not reg.validate_otp(otp_code):
log_cb("[X] OTP 验证失败")
return None
log_cb("[OK] OTP 验证成功")
log_status("API注册", "创建账户...")
if not reg.create_account(real_name, birthdate):
log_cb("[X] 创建账户失败")
return None
log_cb("[OK] 账户创建成功")
# 验证 session 是否有效
token = reg.get_session_token()
if token:
log_cb(f"[OK] Session 有效Token: {token[:30]}...")
else:
log_cb("[!] 注册完成但 session 可能未完全建立")
return reg
except Exception as e:
log_status("错误", f"注册异常: {e}")
return None
def api_login_flow(
email: str,
password: str,
proxy: str = None,
progress_callback=None
) -> ChatGPTAPIRegister:
"""执行 API 登录流程
Args:
email: 邮箱
password: 密码
proxy: 代理地址
progress_callback: 进度回调
Returns:
ChatGPTAPIRegister: 成功返回 reg 对象,失败返回 None
"""
def log_cb(msg):
if progress_callback:
progress_callback(msg)
log_progress(msg)
reg = ChatGPTAPIRegister(proxy=proxy)
try:
log_status("API登录", "初始化会话...")
if not reg.init_session():
log_cb("[X] 初始化失败")
return None
log_cb("[OK] 初始化成功")
log_status("API登录", "获取授权 URL...")
if not reg.get_authorize_url(email):
log_cb("[X] 获取授权 URL 失败")
return None
log_cb("[OK] 获取授权 URL 成功")
log_status("API登录", "开始授权流程...")
if not reg.start_authorize():
log_cb("[X] 授权流程失败")
return None
log_cb("[OK] 授权流程成功")
log_status("API登录", "密码验证...")
if not reg.login(email, password):
log_cb("[X] 登录失败")
return None
log_cb("[OK] 登录成功")
# 获取 token
token = reg.get_session_token()
if token:
log_status("API登录", f"Token: {token[:50]}...")
return reg
except Exception as e:
log_status("错误", f"登录异常: {e}")
return None
def is_api_mode_available() -> bool:
"""检查协议模式是否可用"""
return CURL_CFFI_AVAILABLE
def api_register_account_only(
email: str,
password: str,
real_name: str,
birthdate: str,
get_verification_code_func,
proxy: str = None,
progress_callback=None
) -> bool:
"""仅执行 API 注册流程(不含支付,用于邀请邮箱注册)
Args:
email: 邮箱
password: 密码
real_name: 姓名
birthdate: 生日 (YYYY-MM-DD)
get_verification_code_func: 获取验证码的函数,签名: func(email) -> str
proxy: 代理地址
progress_callback: 进度回调
Returns:
bool: 是否注册成功
"""
def log_cb(msg):
if progress_callback:
progress_callback(msg)
log_progress(msg)
if not CURL_CFFI_AVAILABLE:
log_status("错误", "协议模式不可用,请安装 curl_cffi")
return False
reg = ChatGPTAPIRegister(proxy=proxy)
try:
log_status("API注册", "初始化会话...")
if not reg.init_session():
log_cb("[X] 初始化失败")
return False
log_cb("[OK] 会话初始化成功")
log_status("API注册", "获取授权 URL...")
if not reg.get_authorize_url(email):
log_cb("[X] 获取授权 URL 失败")
return False
log_cb("[OK] 授权 URL 获取成功")
log_status("API注册", "开始授权流程...")
if not reg.start_authorize():
log_cb("[X] 授权流程启动失败")
return False
log_cb("[OK] 授权流程已启动")
log_status("API注册", "注册账户...")
if not reg.register(email, password):
log_cb("[X] 注册失败")
return False
log_cb("[OK] 账户注册成功")
log_status("API注册", "发送验证邮件...")
if not reg.send_verification_email():
log_cb("[X] 发送验证邮件失败")
return False
log_cb("[OK] 验证邮件已发送")
# 使用传入的函数获取验证码
log_status("API注册", "等待验证码...")
otp_code = get_verification_code_func(email)
if not otp_code:
log_cb("[X] 未能获取验证码")
return False
log_status("API注册", f"验证 OTP: {otp_code}")
if not reg.validate_otp(otp_code):
log_cb("[X] OTP 验证失败")
return False
log_cb("[OK] OTP 验证成功")
log_status("API注册", "创建账户...")
if not reg.create_account(real_name, birthdate):
log_cb("[X] 创建账户失败")
return False
log_cb("[OK] 账户创建成功")
# 验证 session 是否有效
token = reg.get_session_token()
if token:
log_cb(f"[OK] 注册完成Token: {token[:30]}...")
return True
else:
log_cb("[!] 注册完成但 session 可能未完全建立")
return True # 仍然返回成功,因为注册流程已完成
except Exception as e:
log_status("错误", f"注册异常: {e}")
return False

View File

@@ -2,7 +2,11 @@
Author: muyyg Author: muyyg
Project: Subscription Automation (DrissionPage Version) Project: Subscription Automation (DrissionPage Version)
Created: 2026-01-12 Created: 2026-01-12
Version: 3.0-drission Version: 3.1-hybrid (支持协议模式)
模式说明:
- browser: 浏览器自动化模式 (默认),全程使用 DrissionPage 浏览器自动化
- api: 协议模式,使用 API 快速完成注册,仅支付环节使用浏览器
""" """
import time import time
@@ -13,10 +17,27 @@ import sys
import os import os
import platform import platform
import subprocess import subprocess
import tempfile
import requests import requests
from pathlib import Path from pathlib import Path
from DrissionPage import ChromiumPage, ChromiumOptions from DrissionPage import ChromiumPage, ChromiumOptions
# 导入协议模式模块
try:
from api_register import (
ChatGPTAPIRegister,
api_register_flow,
api_login_flow,
is_api_mode_available,
get_verification_code_api,
)
API_MODE_AVAILABLE = is_api_mode_available()
except ImportError:
API_MODE_AVAILABLE = False
ChatGPTAPIRegister = None
api_register_flow = None
api_login_flow = None
# ================= 配置加载 ================= # ================= 配置加载 =================
try: try:
import tomllib import tomllib
@@ -63,6 +84,13 @@ SEPA_IBANS = _autogptplus.get("sepa_ibans", [])
# 6. 随机指纹开关 # 6. 随机指纹开关
RANDOM_FINGERPRINT = _autogptplus.get("random_fingerprint", True) RANDOM_FINGERPRINT = _autogptplus.get("random_fingerprint", True)
# 7. 注册模式: "browser" (浏览器自动化) 或 "api" (协议模式)
# 默认使用 API 模式(更快),如果 curl_cffi 不可用则自动回退到浏览器模式
REGISTER_MODE = _autogptplus.get("register_mode", "api")
# 8. 协议模式代理 (仅协议模式使用)
API_PROXY = _autogptplus.get("api_proxy", "")
# ================= 浏览器指纹 ================= # ================= 浏览器指纹 =================
FINGERPRINTS = [ FINGERPRINTS = [
# NVIDIA 显卡 # NVIDIA 显卡
@@ -1198,6 +1226,166 @@ def run_payment_flow(page, email, step_callback=None):
log_status("错误", f"[X] 支付流程异常: {e}") log_status("错误", f"[X] 支付流程异常: {e}")
return None return None
def browser_pay_with_cookies(reg, email: str, proxy: str = None, headless: bool = True, step_callback=None):
"""使用 API 会话的 cookies 注入浏览器完成支付 (协议模式专用)
Args:
reg: ChatGPTAPIRegister 对象
email: 邮箱
proxy: 代理地址
headless: 是否无头模式
step_callback: 步骤回调
Returns:
dict: {"token": ..., "account_id": ...} 或 None
"""
def step_cb(step):
if step_callback:
step_callback(step)
step_cb("获取支付页 URL...")
# 通过 API 获取支付页 URL
checkout_url = reg.get_checkout_url()
if not checkout_url:
log_status("失败", "无法获取支付页 URL")
return None
log_progress(f"[OK] 支付页: {checkout_url[:60]}...")
# 获取 cookies
cookies = reg.get_cookies()
log_status("Cookie", f"获取到 {len(cookies)} 个 cookies")
# 启动浏览器
step_cb("启动浏览器...")
temp_user_data = tempfile.mkdtemp(prefix="chrome_api_")
# 检测操作系统
is_linux = platform.system() == "Linux"
# 获取随机指纹
fingerprint = None
if RANDOM_FINGERPRINT:
fingerprint = get_random_fingerprint()
else:
fingerprint = {
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
"platform": "Win32",
"webgl_vendor": "Google Inc. (NVIDIA)",
"webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0)",
"screen": {"width": 1920, "height": 1080}
}
co = ChromiumOptions()
co.set_argument('--no-first-run')
co.set_argument('--no-default-browser-check')
co.set_argument(f'--user-data-dir={temp_user_data}')
co.set_argument('--disable-blink-features=AutomationControlled')
co.set_argument('--disable-infobars')
co.set_argument('--disable-dev-shm-usage')
co.set_argument('--no-sandbox')
co.set_argument(f'--user-agent={fingerprint["user_agent"]}')
screen = fingerprint.get("screen", {"width": 1920, "height": 1080})
if headless:
co.set_argument('--headless=new')
co.set_argument(f'--window-size={screen["width"]},{screen["height"]}')
else:
co.set_argument(f'--window-size={screen["width"]},{screen["height"]}')
if proxy:
co.set_argument(f'--proxy-server={proxy}')
if is_linux:
co.set_argument('--disable-software-rasterizer')
co.set_argument('--disable-extensions')
co.set_argument('--disable-setuid-sandbox')
co.set_argument('--single-process')
co.set_argument('--remote-debugging-port=0')
chrome_paths = [
'/usr/bin/google-chrome',
'/usr/bin/google-chrome-stable',
'/usr/bin/chromium-browser',
'/usr/bin/chromium',
'/snap/bin/chromium',
]
for chrome_path in chrome_paths:
if os.path.exists(chrome_path):
co.set_browser_path(chrome_path)
break
else:
co.auto_port(True)
co.set_local_port(random.randint(19222, 29999))
log_status("浏览器", f"正在启动 ({'无头' if headless else '有头'}模式)...")
page = ChromiumPage(co)
try:
# 注入指纹
if RANDOM_FINGERPRINT:
inject_fingerprint(page, fingerprint)
# 先访问 chatgpt.com 注入 cookies
step_cb("注入登录状态...")
log_status("Cookie", "注入登录状态...")
page.get("https://chatgpt.com")
injected_count = 0
for cookie in cookies:
try:
if 'chatgpt.com' in cookie.get('domain', ''):
page.set.cookies({
'name': cookie['name'],
'value': cookie['value'],
'domain': cookie['domain'].lstrip('.'),
'path': cookie.get('path', '/'),
})
injected_count += 1
except:
pass
log_progress(f"[OK] 已注入 {injected_count} 个 cookies")
# 刷新页面确保 cookies 生效
time.sleep(1)
page.refresh()
time.sleep(1)
# 直接跳转到支付页
step_cb("跳转到支付页...")
log_status("订阅", "跳转到支付页...")
page.get(checkout_url)
try:
page.wait.url_change('pay.openai.com', timeout=15)
log_progress("✓ 已跳转到支付页")
except:
time.sleep(2)
# 执行支付流程
step_cb("执行 SEPA 支付...")
result = run_payment_flow(page, email, step_cb)
return result
except Exception as e:
log_status("错误", f"浏览器流程异常: {e}")
return None
finally:
try:
page.quit()
except:
pass
# 清理临时目录
try:
import shutil
shutil.rmtree(temp_user_data, ignore_errors=True)
except:
pass
def fetch_account_id(page, access_token: str) -> str: def fetch_account_id(page, access_token: str) -> str:
"""通过 API 获取 account_id (使用 requests 直接请求,更快)""" """通过 API 获取 account_id (使用 requests 直接请求,更快)"""
log_status("获取", "正在获取 account_id...") log_status("获取", "正在获取 account_id...")
@@ -2013,5 +2201,220 @@ def run_single_registration(progress_callback=None, step_callback=None) -> dict:
cleanup_chrome_processes() cleanup_chrome_processes()
def run_single_registration_api(progress_callback=None, step_callback=None, proxy: str = None) -> dict:
"""执行单次注册流程 - 协议模式 (API + Cookie 注入浏览器)
Args:
progress_callback: 进度回调函数 (message: str)
step_callback: 步骤回调函数 (step: str)
proxy: 代理地址
Returns:
dict: {"success": bool, "account": str, "password": str, "token": str, "account_id": str, "error": str}
"""
def log_cb(msg):
if progress_callback:
progress_callback(msg)
log_progress(msg)
def step_cb(step):
if step_callback:
step_callback(step)
# 检查协议模式是否可用
if not API_MODE_AVAILABLE:
return {"success": False, "error": "协议模式不可用,请安装 curl_cffi: pip install curl_cffi"}
# 检查必要配置
if not MAIL_API_TOKEN or not MAIL_API_BASE:
return {"success": False, "error": "配置错误: 请在 config.toml 中配置 [autogptplus] 段"}
# 检查域名
domains = get_email_domains()
if not domains:
return {"success": False, "error": "没有可用的邮箱域名,请先通过 /domain_add 导入"}
# 检查 IBAN
ibans = get_sepa_ibans()
if not ibans:
return {"success": False, "error": "没有可用的 IBAN请先通过 /iban_add 导入"}
step_cb("生成账号信息...")
# 生成账号信息
random_str = ''.join(random.choices(string.ascii_lowercase + string.digits, k=15))
email_domain = random.choice(domains)
email = f"{random_str}{email_domain}"
password = ''.join(random.choices(string.ascii_uppercase, k=2)) + \
''.join(random.choices(string.ascii_lowercase, k=8)) + \
''.join(random.choices(string.digits, k=2)) + \
random.choice('!@#$%')
real_name = f"{random.choice(FIRST_NAMES)} {random.choice(LAST_NAMES)}"
# 生成生日
year = random.randint(2000, 2004)
month = random.randint(1, 12)
if month in [1, 3, 5, 7, 8, 10, 12]:
max_day = 31
elif month in [4, 6, 9, 11]:
max_day = 30
else:
max_day = 29 if year % 4 == 0 else 28
day = random.randint(1, max_day)
birthdate = f"{year}-{month:02d}-{day:02d}"
log_status("初始化", f"生成账号: {email}")
log_status("初始化", f"设置密码: {password}")
log_status("初始化", f"姓名: {real_name} | 生日: {birthdate}")
log_status("模式", "协议模式 (API + Cookie 注入)")
# 使用配置的代理或传入的代理
use_proxy = proxy or API_PROXY or None
if use_proxy:
log_status("代理", f"使用代理: {use_proxy}")
try:
# 阶段 1: API 注册
step_cb("API 快速注册...")
log_status("阶段 1", "========== API 快速注册 ==========")
reg = api_register_flow(
email=email,
password=password,
real_name=real_name,
birthdate=birthdate,
mail_api_base=MAIL_API_BASE,
mail_api_token=MAIL_API_TOKEN,
proxy=use_proxy,
progress_callback=log_cb
)
if not reg:
log_status("失败", "API 注册失败")
return {"success": False, "error": "API 注册失败", "account": email, "password": password}
log_status("完成", "[OK] API 注册成功!")
# 阶段 2: Cookie 注入浏览器 + 支付
step_cb("Cookie 注入浏览器...")
log_status("阶段 2", "========== Cookie 注入浏览器 + 订阅支付 ==========")
result = browser_pay_with_cookies(
reg=reg,
email=email,
proxy=use_proxy,
headless=True,
step_callback=step_cb
)
if result and result.get("stopped"):
log_status("停止", "⚠ 注册被用户停止")
return {"success": False, "error": "用户停止", "stopped": True, "account": email, "password": password}
elif result and result.get("token"):
step_cb("注册成功!")
log_status("完成", "✓ 全部流程完成!")
return {
"success": True,
"account": email,
"password": password,
"token": result["token"],
"account_id": result.get("account_id", "")
}
# 如果 Cookie 注入失败,尝试 API 登录方式
log_status("重试", "Cookie 注入失败,尝试 API 登录...")
step_cb("尝试 API 登录...")
reg2 = api_login_flow(
email=email,
password=password,
proxy=use_proxy,
progress_callback=log_cb
)
if reg2:
result = browser_pay_with_cookies(
reg=reg2,
email=email,
proxy=use_proxy,
headless=True,
step_callback=step_cb
)
if result and result.get("token"):
step_cb("注册成功!")
log_status("完成", "✓ 全部流程完成!")
return {
"success": True,
"account": email,
"password": password,
"token": result["token"],
"account_id": result.get("account_id", "")
}
log_status("失败", "注册成功但支付/获取token失败")
return {"success": False, "error": "支付流程失败", "account": email, "password": password}
except Exception as e:
error_msg = str(e)
if _is_connection_lost(error_msg) or _is_shutdown_requested():
log_status("停止", "⚠ 注册被用户停止")
return {"success": False, "error": "用户停止", "stopped": True, "account": email, "password": password}
log_status("错误", f"注册异常: {e}")
return {"success": False, "error": str(e), "account": email, "password": password}
finally:
cleanup_chrome_processes()
def run_single_registration_auto(progress_callback=None, step_callback=None, mode: str = None) -> dict:
"""自动选择模式执行注册
Args:
progress_callback: 进度回调
step_callback: 步骤回调
mode: 强制指定模式 ("browser" / "api")None 则使用配置
Returns:
dict: 注册结果
"""
use_mode = mode or REGISTER_MODE
if use_mode == "api":
if not API_MODE_AVAILABLE:
log_status("警告", "协议模式不可用,回退到浏览器模式")
return run_single_registration(progress_callback, step_callback)
return run_single_registration_api(progress_callback, step_callback)
else:
return run_single_registration(progress_callback, step_callback)
def get_register_mode() -> str:
"""获取当前注册模式"""
return REGISTER_MODE
def set_register_mode(mode: str) -> bool:
"""设置注册模式 (运行时)
Args:
mode: "browser""api"
Returns:
bool: 是否设置成功
"""
global REGISTER_MODE
if mode in ("browser", "api"):
if mode == "api" and not API_MODE_AVAILABLE:
return False
REGISTER_MODE = mode
return True
return False
def is_api_mode_supported() -> bool:
"""检查协议模式是否支持"""
return API_MODE_AVAILABLE
if __name__ == "__main__": if __name__ == "__main__":
run_main_process() run_main_process()

View File

@@ -1,6 +1,7 @@
# ==================== 浏览器自动化模块 ==================== # ==================== 浏览器自动化模块 ====================
# 处理 OpenAI 注册、Codex 授权等浏览器自动化操作 # 处理 OpenAI 注册、Codex 授权等浏览器自动化操作
# 使用 DrissionPage 替代 Selenium # 使用 DrissionPage 替代 Selenium
# 支持协议模式 (API) 和浏览器模式
import time import time
import random import random
@@ -34,6 +35,17 @@ from s2a_service import (
) )
from logger import log from logger import log
# 导入协议模式模块
try:
from api_register import (
api_register_account_only,
is_api_mode_available as _is_api_mode_available,
)
API_MODE_AVAILABLE = _is_api_mode_available()
except ImportError:
API_MODE_AVAILABLE = False
api_register_account_only = None
# 进度更新 (Telegram Bot 使用) # 进度更新 (Telegram Bot 使用)
try: try:
from bot_notifier import progress_update from bot_notifier import progress_update
@@ -945,6 +957,91 @@ def is_logged_in(page, timeout: int = 5) -> bool:
return False return False
def register_openai_account_api(email: str, password: str, proxy: str = None) -> bool:
"""使用协议模式 (API) 注册 OpenAI 账号
Args:
email: 邮箱地址
password: 密码
proxy: 代理地址 (可选)
Returns:
bool: 是否成功
"""
if not API_MODE_AVAILABLE:
log.warning("协议模式不可用,回退到浏览器模式")
return None # 返回 None 表示需要回退
log.info(f"[API模式] 开始注册 OpenAI 账号: {email}", icon="account")
# 生成随机姓名和生日
random_name = get_random_name()
birthday = get_random_birthday()
birthdate = f"{birthday['year']}-{birthday['month']}-{birthday['day']}"
log.step(f"姓名: {random_name}, 生日: {birthdate}")
# 定义获取验证码的函数
def get_code(target_email):
progress_update(phase="注册", step="等待验证码...")
log.step("等待验证码邮件...")
code, error, email_time = unified_get_verification_code(target_email)
if code:
log.success(f"获取到验证码: {code}")
return code
# 执行 API 注册
try:
result = api_register_account_only(
email=email,
password=password,
real_name=random_name,
birthdate=birthdate,
get_verification_code_func=get_code,
proxy=proxy,
progress_callback=lambda msg: log.step(msg)
)
if result:
log.success(f"[API模式] 注册完成: {email}")
return True
else:
log.warning("[API模式] 注册失败,可能需要回退到浏览器模式")
return False
except Exception as e:
log.error(f"[API模式] 注册异常: {e}")
return False
def register_openai_account_auto(page, email: str, password: str, use_api: bool = True, proxy: str = None) -> bool:
"""自动选择模式注册 OpenAI 账号
优先使用 API 模式,失败则回退到浏览器模式
Args:
page: 浏览器实例 (用于浏览器模式回退)
email: 邮箱地址
password: 密码
use_api: 是否优先使用 API 模式
proxy: 代理地址 (API 模式使用)
Returns:
bool: 是否成功
"""
# 如果启用 API 模式且可用
if use_api and API_MODE_AVAILABLE:
result = register_openai_account_api(email, password, proxy)
if result is True:
return True
elif result is False:
log.warning("API 模式注册失败,回退到浏览器模式...")
# result is None 表示 API 模式不可用,直接使用浏览器模式
# 使用浏览器模式
return register_openai_account(page, email, password)
def register_openai_account(page, email: str, password: str) -> bool: def register_openai_account(page, email: str, password: str) -> bool:
"""使用浏览器注册 OpenAI 账号 """使用浏览器注册 OpenAI 账号
@@ -1976,12 +2073,13 @@ def login_and_authorize_with_otp(email: str) -> tuple[bool, dict]:
return False, None return False, None
def register_and_authorize(email: str, password: str) -> tuple: def register_and_authorize(email: str, password: str, use_api_register: bool = True) -> tuple:
"""完整流程: 注册 OpenAI + Codex 授权 (带重试机制) """完整流程: 注册 OpenAI + Codex 授权 (带重试机制)
Args: Args:
email: 邮箱地址 email: 邮箱地址
password: 密码 password: 密码
use_api_register: 是否优先使用 API 模式注册 (默认 True)
Returns: Returns:
tuple: (register_success, codex_data) tuple: (register_success, codex_data)
@@ -1992,8 +2090,11 @@ def register_and_authorize(email: str, password: str) -> tuple:
with browser_context_with_retry(max_browser_retries=2) as ctx: with browser_context_with_retry(max_browser_retries=2) as ctx:
for attempt in ctx.attempts(): for attempt in ctx.attempts():
try: try:
# 注册 OpenAI # 注册 OpenAI (优先使用 API 模式)
register_result = register_openai_account(ctx.page, email, password) register_result = register_openai_account_auto(
ctx.page, email, password,
use_api=use_api_register
)
# 检查是否是域名黑名单错误 # 检查是否是域名黑名单错误
if register_result == "domain_blacklisted": if register_result == "domain_blacklisted":

View File

@@ -234,3 +234,12 @@ email_domains = ["@example.com", "@example.org"]
sepa_ibans = [] sepa_ibans = []
# 是否启用随机指纹 (User-Agent, WebGL, 分辨率等) # 是否启用随机指纹 (User-Agent, WebGL, 分辨率等)
random_fingerprint = true random_fingerprint = true
# 注册模式选择:
# - "api": 协议模式 (默认),使用 API 快速完成注册,仅支付环节使用浏览器
# 协议模式更快,需要安装 curl_cffi: pip install curl_cffi
# - "browser": 浏览器自动化模式,全程使用 DrissionPage 浏览器自动化
register_mode = "api"
# 协议模式代理 (仅协议模式使用,格式: http://127.0.0.1:7890)
api_proxy = ""

View File

@@ -5,6 +5,7 @@ description = "OpenAI Team 账号自动批量注册 & CRS 入库工具"
readme = "README.md" readme = "README.md"
requires-python = ">=3.12" requires-python = ">=3.12"
dependencies = [ dependencies = [
"curl-cffi>=0.14.0",
"drissionpage>=4.1.1.2", "drissionpage>=4.1.1.2",
"python-telegram-bot[job-queue]>=22.5", "python-telegram-bot[job-queue]>=22.5",
"requests>=2.32.5", "requests>=2.32.5",

View File

@@ -4,3 +4,6 @@ requests>=2.32.5
rich>=14.2.0 rich>=14.2.0
setuptools>=80.9.0 setuptools>=80.9.0
tomli>=2.3.0 tomli>=2.3.0
# 协议模式依赖 (可选,用于 API 快速注册)
curl_cffi>=0.7.0

View File

@@ -2862,7 +2862,7 @@ class ProvisionerBot:
async def _run_team_registration(self, chat_id: int, count: int, output_type: str): async def _run_team_registration(self, chat_id: int, count: int, output_type: str):
"""执行 GPT Team 注册任务""" """执行 GPT Team 注册任务"""
from auto_gpt_team import run_single_registration, cleanup_chrome_processes from auto_gpt_team import run_single_registration_auto, cleanup_chrome_processes, get_register_mode
import json import json
import threading import threading
@@ -2870,6 +2870,10 @@ class ProvisionerBot:
success_count = 0 success_count = 0
fail_count = 0 fail_count = 0
# 获取当前注册模式
current_mode = get_register_mode()
mode_display = "🌐 协议模式" if current_mode == "api" else "🖥️ 浏览器模式"
# 当前步骤 (用于显示) # 当前步骤 (用于显示)
current_step = ["初始化..."] current_step = ["初始化..."]
current_account = [""] current_account = [""]
@@ -2884,6 +2888,7 @@ class ProvisionerBot:
progress_msg = await self.app.bot.send_message( progress_msg = await self.app.bot.send_message(
chat_id, chat_id,
f"<b>🚀 开始注册</b>\n\n" f"<b>🚀 开始注册</b>\n\n"
f"模式: {mode_display}\n"
f"进度: 0/{count}\n" f"进度: 0/{count}\n"
f"{'' * 20}", f"{'' * 20}",
parse_mode="HTML" parse_mode="HTML"
@@ -2908,6 +2913,7 @@ class ProvisionerBot:
text = ( text = (
f"<b>🚀 注册中...</b>\n\n" f"<b>🚀 注册中...</b>\n\n"
f"模式: {mode_display}\n"
f"进度: {success_count + fail_count}/{count}\n" f"进度: {success_count + fail_count}/{count}\n"
f"{progress_bar}\n\n" f"{progress_bar}\n\n"
f"✅ 成功: {success_count}\n" f"✅ 成功: {success_count}\n"
@@ -2947,7 +2953,7 @@ class ProvisionerBot:
import functools import functools
def run_with_callback(): def run_with_callback():
return run_single_registration( return run_single_registration_auto(
progress_callback=None, progress_callback=None,
step_callback=step_callback step_callback=step_callback
) )
@@ -3094,7 +3100,16 @@ class ProvisionerBot:
def _get_autogptplus_main_keyboard(self): def _get_autogptplus_main_keyboard(self):
"""获取 AutoGPTPlus 主菜单键盘""" """获取 AutoGPTPlus 主菜单键盘"""
return InlineKeyboardMarkup([ # 检查协议模式是否可用
try:
from auto_gpt_team import is_api_mode_supported, get_register_mode
api_supported = is_api_mode_supported()
current_mode = get_register_mode()
except ImportError:
api_supported = False
current_mode = "browser"
keyboard = [
[ [
InlineKeyboardButton("📋 查看配置", callback_data="autogptplus:config"), InlineKeyboardButton("📋 查看配置", callback_data="autogptplus:config"),
InlineKeyboardButton("🔑 设置 Token", callback_data="autogptplus:set_token"), InlineKeyboardButton("🔑 设置 Token", callback_data="autogptplus:set_token"),
@@ -3111,10 +3126,20 @@ class ProvisionerBot:
InlineKeyboardButton("📧 测试邮件", callback_data="autogptplus:test_email"), InlineKeyboardButton("📧 测试邮件", callback_data="autogptplus:test_email"),
InlineKeyboardButton("🔄 测试 API", callback_data="autogptplus:test_api"), InlineKeyboardButton("🔄 测试 API", callback_data="autogptplus:test_api"),
], ],
[ ]
InlineKeyboardButton("🚀 开始注册", callback_data="autogptplus:register"),
], # 添加注册模式选择按钮
mode_icon = "🌐" if current_mode == "api" else "🖥️"
mode_text = "协议模式" if current_mode == "api" else "浏览器模式"
keyboard.append([
InlineKeyboardButton(f"⚙️ 注册模式: {mode_icon} {mode_text}", callback_data="autogptplus:select_mode"),
]) ])
keyboard.append([
InlineKeyboardButton("🚀 开始注册", callback_data="autogptplus:register"),
])
return InlineKeyboardMarkup(keyboard)
async def callback_autogptplus(self, update: Update, context: ContextTypes.DEFAULT_TYPE): async def callback_autogptplus(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""处理 AutoGPTPlus 回调""" """处理 AutoGPTPlus 回调"""
@@ -3148,6 +3173,11 @@ class ProvisionerBot:
await self._toggle_autogptplus_fingerprint(query) await self._toggle_autogptplus_fingerprint(query)
elif action == "stats": elif action == "stats":
await self._show_autogptplus_stats(query) await self._show_autogptplus_stats(query)
elif action == "select_mode":
await self._show_autogptplus_mode_selection(query)
elif action == "set_mode":
await self._set_autogptplus_mode(query, sub_action)
elif action == "register": elif action == "register":
await self._start_autogptplus_register(query, context) await self._start_autogptplus_register(query, context)
elif action == "back": elif action == "back":
@@ -3203,7 +3233,8 @@ class ProvisionerBot:
try: try:
from auto_gpt_team import ( from auto_gpt_team import (
MAIL_API_TOKEN, MAIL_API_BASE, EMAIL_DOMAINS, MAIL_API_TOKEN, MAIL_API_BASE, EMAIL_DOMAINS,
SEPA_IBANS, RANDOM_FINGERPRINT, get_email_domains, get_sepa_ibans SEPA_IBANS, RANDOM_FINGERPRINT, get_email_domains, get_sepa_ibans,
REGISTER_MODE, API_PROXY, is_api_mode_supported
) )
# 脱敏显示 Token # 脱敏显示 Token
@@ -3226,6 +3257,19 @@ class ProvisionerBot:
# 随机指纹状态 # 随机指纹状态
fingerprint_status = "✅ 已开启" if RANDOM_FINGERPRINT else "❌ 已关闭" fingerprint_status = "✅ 已开启" if RANDOM_FINGERPRINT else "❌ 已关闭"
# 注册模式
api_supported = is_api_mode_supported()
if REGISTER_MODE == "api":
mode_display = "🌐 协议模式 (API)"
else:
mode_display = "🖥️ 浏览器模式"
if not api_supported:
mode_display += " (协议模式不可用)"
# 代理配置
proxy_display = API_PROXY if API_PROXY else "未配置"
lines = [ lines = [
"<b>📋 AutoGPTPlus 配置</b>", "<b>📋 AutoGPTPlus 配置</b>",
"", "",
@@ -3240,8 +3284,10 @@ class ProvisionerBot:
"<b>💳 SEPA IBAN</b>", "<b>💳 SEPA IBAN</b>",
f" 数量: {len(ibans)}", f" 数量: {len(ibans)}",
"", "",
"<b>🎭 随机指纹</b>", "<b>⚙️ 注册设置</b>",
f" 状态: {fingerprint_status}", f" 模式: {mode_display}",
f" 随机指纹: {fingerprint_status}",
f" API 代理: {proxy_display}",
] ]
# 配置状态检查 # 配置状态检查
@@ -3731,6 +3777,208 @@ class ProvisionerBot:
reply_markup=reply_markup reply_markup=reply_markup
) )
async def _show_autogptplus_mode_selection(self, query):
"""显示注册模式选择界面"""
try:
from auto_gpt_team import is_api_mode_supported, get_register_mode
api_supported = is_api_mode_supported()
current_mode = get_register_mode()
lines = [
"<b>⚙️ 选择注册模式</b>\n",
"请选择 ChatGPT Team 注册使用的方式:\n",
]
# 浏览器模式说明
browser_check = "" if current_mode == "browser" else ""
lines.append(f"<b>{browser_check} 🖥️ 浏览器模式</b>")
lines.append("全程使用 DrissionPage 浏览器自动化")
lines.append("• 兼容性好,无需额外依赖")
lines.append("• 速度较慢,资源占用较高")
lines.append("")
# 协议模式说明
api_check = "" if current_mode == "api" else ""
api_status = "" if api_supported else " (不可用)"
lines.append(f"<b>{api_check} 🌐 协议模式{api_status}</b>")
lines.append("使用 API 快速注册,仅支付环节用浏览器")
lines.append("• 速度快,资源占用少")
lines.append("• 需要 curl_cffi 依赖")
if not api_supported:
lines.append("• <i>请安装: pip install curl_cffi</i>")
# 构建按钮
keyboard = []
# 浏览器模式按钮
browser_icon = "" if current_mode == "browser" else "🖥️"
keyboard.append([
InlineKeyboardButton(
f"{browser_icon} 浏览器模式",
callback_data="autogptplus:set_mode:browser"
)
])
# 协议模式按钮
if api_supported:
api_icon = "" if current_mode == "api" else "🌐"
keyboard.append([
InlineKeyboardButton(
f"{api_icon} 协议模式 (推荐)",
callback_data="autogptplus:set_mode:api"
)
])
else:
keyboard.append([
InlineKeyboardButton(
"🌐 协议模式 (需安装依赖)",
callback_data="autogptplus:set_mode:api_unavailable"
)
])
keyboard.append([
InlineKeyboardButton("◀️ 返回", callback_data="autogptplus:back")
])
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
"\n".join(lines),
parse_mode="HTML",
reply_markup=reply_markup
)
except ImportError as e:
keyboard = [[InlineKeyboardButton("◀️ 返回", callback_data="autogptplus:back")]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
f"<b>❌ 模块导入失败</b>\n\n{e}",
parse_mode="HTML",
reply_markup=reply_markup
)
except Exception as e:
keyboard = [[InlineKeyboardButton("◀️ 返回", callback_data="autogptplus:back")]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
f"<b>❌ 获取配置失败</b>\n\n{e}",
parse_mode="HTML",
reply_markup=reply_markup
)
async def _set_autogptplus_mode(self, query, mode: str):
"""设置注册模式"""
import tomli_w
try:
from auto_gpt_team import is_api_mode_supported, get_register_mode, set_register_mode
# 处理协议模式不可用的情况
if mode == "api_unavailable":
keyboard = [[InlineKeyboardButton("◀️ 返回", callback_data="autogptplus:select_mode")]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
"<b>❌ 协议模式不可用</b>\n\n"
"需要安装 curl_cffi 依赖:\n"
"<code>pip install curl_cffi</code>\n\n"
"安装后重启程序即可使用协议模式",
parse_mode="HTML",
reply_markup=reply_markup
)
return
# 检查是否已经是当前模式
current_mode = get_register_mode()
if mode == current_mode:
await query.answer(f"当前已是{'协议' if mode == 'api' else '浏览器'}模式", show_alert=False)
return
# 检查协议模式是否可用
if mode == "api" and not is_api_mode_supported():
keyboard = [[InlineKeyboardButton("◀️ 返回", callback_data="autogptplus:select_mode")]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
"<b>❌ 协议模式不可用</b>\n\n"
"需要安装 curl_cffi 依赖:\n"
"<code>pip install curl_cffi</code>\n\n"
"安装后重启程序即可使用协议模式",
parse_mode="HTML",
reply_markup=reply_markup
)
return
# 读取当前配置
with open(CONFIG_FILE, "rb") as f:
import tomllib
config = tomllib.load(f)
# 确保 autogptplus section 存在
if "autogptplus" not in config:
config["autogptplus"] = {}
# 更新配置
config["autogptplus"]["register_mode"] = mode
# 写回文件
with open(CONFIG_FILE, "wb") as f:
tomli_w.dump(config, f)
# 更新运行时配置
set_register_mode(mode)
# 重新加载模块
import importlib
import auto_gpt_team
importlib.reload(auto_gpt_team)
# 显示成功消息
if mode == "api":
mode_name = "🌐 协议模式"
mode_desc = (
"使用 API 快速完成注册流程,仅支付环节使用浏览器\n\n"
"<b>特点:</b>\n"
"• 注册速度更快\n"
"• 资源占用更少\n"
"• 更稳定可靠"
)
else:
mode_name = "🖥️ 浏览器模式"
mode_desc = (
"全程使用 DrissionPage 浏览器自动化\n\n"
"<b>特点:</b>\n"
"• 兼容性更好\n"
"• 无需额外依赖\n"
"• 可视化调试方便"
)
keyboard = [[InlineKeyboardButton("◀️ 返回主菜单", callback_data="autogptplus:back")]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
f"<b>✅ 注册模式已设置</b>\n\n"
f"当前模式: {mode_name}\n\n"
f"{mode_desc}",
parse_mode="HTML",
reply_markup=reply_markup
)
except ImportError as e:
keyboard = [[InlineKeyboardButton("◀️ 返回", callback_data="autogptplus:back")]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
f"<b>❌ 模块导入失败</b>\n\n{e}",
parse_mode="HTML",
reply_markup=reply_markup
)
except Exception as e:
keyboard = [[InlineKeyboardButton("◀️ 返回", callback_data="autogptplus:back")]]
reply_markup = InlineKeyboardMarkup(keyboard)
await query.edit_message_text(
f"<b>❌ 设置失败</b>\n\n{e}",
parse_mode="HTML",
reply_markup=reply_markup
)
async def _show_autogptplus_stats(self, query): async def _show_autogptplus_stats(self, query):
"""显示统计信息""" """显示统计信息"""
try: try:

91
uv.lock generated
View File

@@ -36,6 +36,63 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" },
] ]
[[package]]
name = "cffi"
version = "2.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pycparser", marker = "implementation_name != 'PyPy'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" },
{ url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" },
{ url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" },
{ url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" },
{ url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" },
{ url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" },
{ url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" },
{ url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" },
{ url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" },
{ url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" },
{ url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" },
{ url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" },
{ url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" },
{ url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" },
{ url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" },
{ url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" },
{ url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" },
{ url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" },
{ url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" },
{ url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" },
{ url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" },
{ url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" },
{ url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" },
{ url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" },
{ url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" },
{ url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" },
{ url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
{ url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
{ url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
{ url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
{ url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
{ url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
{ url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
{ url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
{ url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
{ url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" },
{ url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" },
{ url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
{ url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
{ url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
{ url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
{ url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
{ url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
{ url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
{ url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
{ url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
]
[[package]] [[package]]
name = "charset-normalizer" name = "charset-normalizer"
version = "3.4.4" version = "3.4.4"
@@ -123,6 +180,29 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ee/58/257350f7db99b4ae12b614a36256d9cc870d71d9e451e79c2dc3b23d7c3c/cssselect-1.3.0-py3-none-any.whl", hash = "sha256:56d1bf3e198080cc1667e137bc51de9cadfca259f03c2d4e09037b3e01e30f0d", size = 18786, upload-time = "2025-03-10T09:30:28.048Z" }, { url = "https://files.pythonhosted.org/packages/ee/58/257350f7db99b4ae12b614a36256d9cc870d71d9e451e79c2dc3b23d7c3c/cssselect-1.3.0-py3-none-any.whl", hash = "sha256:56d1bf3e198080cc1667e137bc51de9cadfca259f03c2d4e09037b3e01e30f0d", size = 18786, upload-time = "2025-03-10T09:30:28.048Z" },
] ]
[[package]]
name = "curl-cffi"
version = "0.14.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "cffi" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9b/c9/0067d9a25ed4592b022d4558157fcdb6e123516083700786d38091688767/curl_cffi-0.14.0.tar.gz", hash = "sha256:5ffbc82e59f05008ec08ea432f0e535418823cda44178ee518906a54f27a5f0f", size = 162633, upload-time = "2025-12-16T03:25:07.931Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/aa/f0/0f21e9688eaac85e705537b3a87a5588d0cefb2f09d83e83e0e8be93aa99/curl_cffi-0.14.0-cp39-abi3-macosx_14_0_arm64.whl", hash = "sha256:e35e89c6a69872f9749d6d5fda642ed4fc159619329e99d577d0104c9aad5893", size = 3087277, upload-time = "2025-12-16T03:24:49.607Z" },
{ url = "https://files.pythonhosted.org/packages/ba/a3/0419bd48fce5b145cb6a2344c6ac17efa588f5b0061f212c88e0723da026/curl_cffi-0.14.0-cp39-abi3-macosx_15_0_x86_64.whl", hash = "sha256:5945478cd28ad7dfb5c54473bcfb6743ee1d66554d57951fdf8fc0e7d8cf4e45", size = 5804650, upload-time = "2025-12-16T03:24:51.518Z" },
{ url = "https://files.pythonhosted.org/packages/e2/07/a238dd062b7841b8caa2fa8a359eb997147ff3161288f0dd46654d898b4d/curl_cffi-0.14.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c42e8fa3c667db9ccd2e696ee47adcd3cd5b0838d7282f3fc45f6c0ef3cfdfa7", size = 8231918, upload-time = "2025-12-16T03:24:52.862Z" },
{ url = "https://files.pythonhosted.org/packages/7c/d2/ce907c9b37b5caf76ac08db40cc4ce3d9f94c5500db68a195af3513eacbc/curl_cffi-0.14.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:060fe2c99c41d3cb7f894de318ddf4b0301b08dca70453d769bd4e74b36b8483", size = 8654624, upload-time = "2025-12-16T03:24:54.579Z" },
{ url = "https://files.pythonhosted.org/packages/f2/ae/6256995b18c75e6ef76b30753a5109e786813aa79088b27c8eabb1ef85c9/curl_cffi-0.14.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b158c41a25388690dd0d40b5bc38d1e0f512135f17fdb8029868cbc1993d2e5b", size = 8010654, upload-time = "2025-12-16T03:24:56.507Z" },
{ url = "https://files.pythonhosted.org/packages/fb/10/ff64249e516b103cb762e0a9dca3ee0f04cf25e2a1d5d9838e0f1273d071/curl_cffi-0.14.0-cp39-abi3-manylinux_2_28_i686.whl", hash = "sha256:1439fbef3500fb723333c826adf0efb0e2e5065a703fb5eccce637a2250db34a", size = 7781969, upload-time = "2025-12-16T03:24:57.885Z" },
{ url = "https://files.pythonhosted.org/packages/51/76/d6f7bb76c2d12811aa7ff16f5e17b678abdd1b357b9a8ac56310ceccabd5/curl_cffi-0.14.0-cp39-abi3-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e7176f2c2d22b542e3cf261072a81deb018cfa7688930f95dddef215caddb469", size = 7969133, upload-time = "2025-12-16T03:24:59.261Z" },
{ url = "https://files.pythonhosted.org/packages/23/7c/cca39c0ed4e1772613d3cba13091c0e9d3b89365e84b9bf9838259a3cd8f/curl_cffi-0.14.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:03f21ade2d72978c2bb8670e9b6de5260e2755092b02d94b70b906813662998d", size = 9080167, upload-time = "2025-12-16T03:25:00.946Z" },
{ url = "https://files.pythonhosted.org/packages/75/03/a942d7119d3e8911094d157598ae0169b1c6ca1bd3f27d7991b279bcc45b/curl_cffi-0.14.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:58ebf02de64ee5c95613209ddacb014c2d2f86298d7080c0a1c12ed876ee0690", size = 9520464, upload-time = "2025-12-16T03:25:02.922Z" },
{ url = "https://files.pythonhosted.org/packages/a2/77/78900e9b0833066d2274bda75cba426fdb4cef7fbf6a4f6a6ca447607bec/curl_cffi-0.14.0-cp39-abi3-win_amd64.whl", hash = "sha256:6e503f9a103f6ae7acfb3890c843b53ec030785a22ae7682a22cc43afb94123e", size = 1677416, upload-time = "2025-12-16T03:25:04.902Z" },
{ url = "https://files.pythonhosted.org/packages/5c/7c/d2ba86b0b3e1e2830bd94163d047de122c69a8df03c5c7c36326c456ad82/curl_cffi-0.14.0-cp39-abi3-win_arm64.whl", hash = "sha256:2eed50a969201605c863c4c31269dfc3e0da52916086ac54553cfa353022425c", size = 1425067, upload-time = "2025-12-16T03:25:06.454Z" },
]
[[package]] [[package]]
name = "datarecorder" name = "datarecorder"
version = "3.6.2" version = "3.6.2"
@@ -337,6 +417,7 @@ name = "oai-team-auto-provisioner"
version = "0.1.0" version = "0.1.0"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "curl-cffi" },
{ name = "drissionpage" }, { name = "drissionpage" },
{ name = "python-telegram-bot", extra = ["job-queue"] }, { name = "python-telegram-bot", extra = ["job-queue"] },
{ name = "requests" }, { name = "requests" },
@@ -348,6 +429,7 @@ dependencies = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "curl-cffi", specifier = ">=0.14.0" },
{ name = "drissionpage", specifier = ">=4.1.1.2" }, { name = "drissionpage", specifier = ">=4.1.1.2" },
{ name = "python-telegram-bot", extras = ["job-queue"], specifier = ">=22.5" }, { name = "python-telegram-bot", extras = ["job-queue"], specifier = ">=22.5" },
{ name = "requests", specifier = ">=2.32.5" }, { name = "requests", specifier = ">=2.32.5" },
@@ -395,6 +477,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c9/ad/33b2ccec09bf96c2b2ef3f9a6f66baac8253d7565d8839e024a6b905d45d/psutil-7.1.3-cp37-abi3-win_arm64.whl", hash = "sha256:bd0d69cee829226a761e92f28140bec9a5ee9d5b4fb4b0cc589068dbfff559b1", size = 244608, upload-time = "2025-11-02T12:26:36.136Z" }, { url = "https://files.pythonhosted.org/packages/c9/ad/33b2ccec09bf96c2b2ef3f9a6f66baac8253d7565d8839e024a6b905d45d/psutil-7.1.3-cp37-abi3-win_arm64.whl", hash = "sha256:bd0d69cee829226a761e92f28140bec9a5ee9d5b4fb4b0cc589068dbfff559b1", size = 244608, upload-time = "2025-11-02T12:26:36.136Z" },
] ]
[[package]]
name = "pycparser"
version = "3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
]
[[package]] [[package]]
name = "pygments" name = "pygments"
version = "2.19.2" version = "2.19.2"