协议
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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
624
api_register.py
Normal 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
|
||||||
405
auto_gpt_team.py
405
auto_gpt_team.py
@@ -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()
|
||||||
|
|||||||
@@ -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":
|
||||||
|
|||||||
@@ -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 = ""
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
266
telegram_bot.py
266
telegram_bot.py
@@ -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
91
uv.lock
generated
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user