实现邮箱API集成和注册数量限制功能

This commit is contained in:
hkyc
2025-05-22 22:43:44 +08:00
parent 4ee6a2e195
commit 3fb99d17e0
5 changed files with 348 additions and 70 deletions

View File

@@ -8,16 +8,17 @@ from tkinter import filedialog
from ThreadManagerWithPyno import GUIThreadManagerWithPyno
from PynoCaptchaSolver import PynoCaptchaConfig, PynoCaptchaSolver
from SteamCaptchaHelper import SteamCaptchaHelper
from EmailAPIClient import EmailAPIClient
import time
# 配置日志
from loguru import logger
logger.add("steam_registration_pyno.log", rotation="10 MB")
logger.add("steam_registration.log", rotation="10 MB")
class RegistrationGUIWithPynoV2:
class SteamRegistrationGUI:
def __init__(self, root):
self.root = root
self.root.title("Steam注册 - PyNoCaptcha V2")
self.root.title("Steam账号注册助手")
self.root.geometry("800x800")
self.root.minsize(800, 800) # 设置最小窗口大小
@@ -30,7 +31,7 @@ class RegistrationGUIWithPynoV2:
top_frame.pack(fill="x", side="top", padx=5, pady=5)
# 创建配置框架
config_frame = ttk.LabelFrame(top_frame, text="配置信息")
config_frame = ttk.LabelFrame(top_frame, text="基本配置")
config_frame.pack(fill="x", padx=5, pady=5)
# 加载默认配置
@@ -42,11 +43,11 @@ class RegistrationGUIWithPynoV2:
self.config_vars = {}
self._create_config_widgets(config_frame)
# 创建PyNoCaptcha配置框架
captcha_frame = ttk.LabelFrame(top_frame, text="PyNoCaptcha配置")
# 创建验证码配置框架
captcha_frame = ttk.LabelFrame(top_frame, text="验证码配置")
captcha_frame.pack(fill="x", padx=5, pady=5)
# 创建PyNoCaptcha配置输入框
# 创建验证码配置输入框
self.captcha_vars = {}
self._create_captcha_widgets(captcha_frame)
@@ -71,17 +72,51 @@ class RegistrationGUIWithPynoV2:
ttk.Button(steam_frame, text="刷新验证信息",
command=self._refresh_steam_info).grid(row=3, column=0, columnspan=2, padx=5, pady=5)
# 创建邮箱选项框架
email_option_frame = ttk.LabelFrame(top_frame, text="邮箱设置")
email_option_frame.pack(fill="x", padx=5, pady=5)
# 添加邮箱来源选择
self.email_source_var = tk.StringVar(value="txt_file")
email_source_options = [
("自建邮箱API", "api"),
("本地文件", "txt_file"),
("微软Graph", "graph")
]
# 注册数量设置
reg_count_frame = ttk.Frame(email_option_frame)
reg_count_frame.pack(fill="x", padx=5, pady=5)
ttk.Label(reg_count_frame, text="注册数量:").grid(row=0, column=0, padx=5, pady=2, sticky="e")
self.reg_count_var = tk.StringVar(value="10")
ttk.Entry(reg_count_frame, textvariable=self.reg_count_var, width=10).grid(row=0, column=1, padx=5, pady=2, sticky="w")
ttk.Label(reg_count_frame, text="(0表示不限制)").grid(row=0, column=2, padx=5, pady=2, sticky="w")
# 邮箱来源选择
email_source_frame = ttk.Frame(email_option_frame)
email_source_frame.pack(fill="x", padx=5, pady=5)
for i, (text, value) in enumerate(email_source_options):
ttk.Radiobutton(
email_source_frame,
text=text,
variable=self.email_source_var,
value=value,
command=self._toggle_email_source
).grid(row=0, column=i, padx=10, pady=2)
# 创建文件选择框架
files_frame = ttk.LabelFrame(top_frame, text="文件选择")
files_frame.pack(fill="x", padx=5, pady=5)
self.files_frame = ttk.LabelFrame(top_frame, text="文件选择")
self.files_frame.pack(fill="x", padx=5, pady=5)
# 邮箱文件选择
self.email_path = tk.StringVar(value=os.path.join(self.script_dir, 'email_password.txt'))
self._create_file_selector(files_frame, "邮箱文件:", self.email_path, 0)
self._create_file_selector(self.files_frame, "邮箱文件:", self.email_path, 0)
# 代理文件选择
self.proxy_path = tk.StringVar(value=os.path.join(self.script_dir, 'proxy_ips.txt'))
self._create_file_selector(files_frame, "代理文件:", self.proxy_path, 1)
self._create_file_selector(self.files_frame, "代理文件:", self.proxy_path, 1)
# 按钮框架 - 直接放在主界面上,任务列表上方
button_frame = ttk.Frame(main_frame)
@@ -92,7 +127,7 @@ class RegistrationGUIWithPynoV2:
button_frame,
text="开始注册",
command=self.start_registration,
width=20
width=15
)
self.start_button.pack(side="left", padx=10, pady=5, expand=True)
@@ -102,7 +137,7 @@ class RegistrationGUIWithPynoV2:
text="停止注册",
command=self.stop_registration,
state="disabled",
width=20
width=15
)
self.stop_button.pack(side="left", padx=10, pady=5, expand=True)
@@ -111,10 +146,19 @@ class RegistrationGUIWithPynoV2:
button_frame,
text="测试验证码",
command=self.test_captcha,
width=20
width=15
)
self.test_captcha_button.pack(side="left", padx=10, pady=5, expand=True)
# 添加获取邮箱测试按钮
self.test_email_button = ttk.Button(
button_frame,
text="测试邮箱API",
command=self.test_email_api,
width=15
)
self.test_email_button.pack(side="left", padx=10, pady=5, expand=True)
# 中间框架 - 包含任务状态表格
middle_frame = ttk.Frame(main_frame)
middle_frame.pack(fill="both", expand=True, padx=5, pady=5)
@@ -162,9 +206,31 @@ class RegistrationGUIWithPynoV2:
self._stop_progress_update = False
# 添加版本标签
version_label = ttk.Label(main_frame, text="PyNoCaptcha V2 版本", foreground="blue")
version_label = ttk.Label(main_frame, text="Steam账号注册助手 V3.0", foreground="blue")
version_label.pack(side="bottom", padx=5, pady=5)
# 初始化邮箱API客户端
self.email_api_client = EmailAPIClient()
# 初始设置邮箱来源
self._toggle_email_source()
def _toggle_email_source(self):
"""根据邮箱来源选择切换界面显示"""
source = self.email_source_var.get()
# 首先隐藏所有与邮箱相关的文件选择框
for widget in self.files_frame.winfo_children():
if "邮箱文件" in str(widget):
widget.grid_remove()
# 根据所选邮箱来源显示相应控件
if source == "txt_file":
# 显示邮箱文件选择框
for widget in self.files_frame.winfo_children():
if "邮箱文件" in str(widget):
widget.grid()
def _refresh_steam_info(self):
"""刷新Steam验证信息"""
threading.Thread(target=self._refresh_steam_info_thread, daemon=True).start()
@@ -209,11 +275,11 @@ class RegistrationGUIWithPynoV2:
]
for i, (key, label, options) in enumerate(config_items):
ttk.Label(parent, text=label,width=10).grid(row=i, column=0, padx=5, pady=2, sticky="e")
ttk.Label(parent, text=label, width=10).grid(row=i, column=0, padx=5, pady=2, sticky="e")
if options:
var = tk.StringVar(value=str(self.config.get(key, "")))
widget = ttk.Combobox(parent, textvariable=var, values=options,width=50)
widget = ttk.Combobox(parent, textvariable=var, values=options, width=50)
else:
var = tk.StringVar(value=str(self.config.get(key, "")))
widget = ttk.Entry(parent, textvariable=var, width=50)
@@ -222,22 +288,22 @@ class RegistrationGUIWithPynoV2:
self.config_vars[key] = var
def _create_captcha_widgets(self, parent):
"""创建PyNoCaptcha配置输入控件"""
"""创建验证码配置输入控件"""
captcha_items = [
("pyno_user_token", "PyNoCaptcha API密钥:", None),
("pyno_sitekey", "验证码网站Key:", None),
("pyno_referer", "网站Referer:", None),
("pyno_user_token", "API密钥:", None),
("pyno_sitekey", "网站Key:", None),
("pyno_referer", "Referer:", None),
("pyno_user_agent", "User-Agent:", None),
("pyno_timeout", "超时时间(秒):", None),
("pyno_debug", "调试模式:", ["True", "False"])
]
for i, (key, label, options) in enumerate(captcha_items):
ttk.Label(parent, text=label,width=12).grid(row=i, column=0, padx=5, pady=2, sticky="e")
ttk.Label(parent, text=label, width=10).grid(row=i, column=0, padx=5, pady=2, sticky="e")
if options:
var = tk.StringVar(value=str(self.config.get(key, "True" if key == "pyno_debug" else "False")))
widget = ttk.Combobox(parent, textvariable=var, values=options,width=50)
widget = ttk.Combobox(parent, textvariable=var, values=options, width=50)
else:
default_value = ""
if key == "pyno_sitekey":
@@ -334,7 +400,7 @@ class RegistrationGUIWithPynoV2:
value = value.lower() == "true"
config[key] = value
# 保存PyNoCaptcha配置
# 保存验证码配置
for key, var in self.captcha_vars.items():
value = var.get()
if key == "pyno_timeout":
@@ -343,6 +409,10 @@ class RegistrationGUIWithPynoV2:
value = value.lower() == "true"
config[key] = value
# 保存邮箱来源配置
config['email_source'] = self.email_source_var.get()
config['reg_count'] = int(self.reg_count_var.get())
with open(self.config_path, 'w') as f:
json.dump(config, f, indent=2)
return True
@@ -352,7 +422,9 @@ class RegistrationGUIWithPynoV2:
def _validate_inputs(self):
"""验证输入"""
if not os.path.exists(self.email_path.get()):
# 检查邮箱来源
email_source = self.email_source_var.get()
if email_source == "txt_file" and not os.path.exists(self.email_path.get()):
messagebox.showerror("错误", "邮箱文件不存在")
return False
@@ -366,17 +438,27 @@ class RegistrationGUIWithPynoV2:
messagebox.showerror("错误", f"请填写 {key} 配置项")
return False
# 验证PyNoCaptcha配置
# 验证验证码配置
required_captcha_keys = ["pyno_user_token"]
for key in required_captcha_keys:
if not self.captcha_vars[key].get().strip():
messagebox.showerror("错误", f"请填写 {key} 配置项")
return False
# 验证注册数量
try:
count = int(self.reg_count_var.get())
if count < 0:
messagebox.showerror("错误", "注册数量不能为负数")
return False
except ValueError:
messagebox.showerror("错误", "注册数量必须是整数")
return False
return True
def get_captcha_config(self):
"""获取PyNoCaptcha配置"""
"""获取验证码配置"""
return PynoCaptchaConfig(
user_token=self.captcha_vars["pyno_user_token"].get(),
sitekey=self.captcha_vars["pyno_sitekey"].get(),
@@ -386,11 +468,52 @@ class RegistrationGUIWithPynoV2:
debug=self.captcha_vars["pyno_debug"].get().lower() == "true"
)
def test_email_api(self):
"""测试邮箱API功能"""
# 禁用测试按钮
self.test_email_button.config(state="disabled")
# 在新线程中测试
threading.Thread(target=self._test_email_api_thread, daemon=True).start()
def _test_email_api_thread(self):
"""在新线程中测试邮箱API"""
try:
test_id = "测试邮箱API"
self.update_status(test_id, status="正在从API获取邮箱...")
# 获取邮箱账号
email_data = self.email_api_client.get_email_credentials()
if not email_data:
self.update_status(test_id, status="获取邮箱失败", result="失败")
messagebox.showerror("错误", "无法从API获取邮箱账号")
return
# 显示结果
self.update_status(
test_id,
status=f"获取邮箱成功: {email_data['email']}",
account_name="N/A",
password=email_data['password'],
result="成功"
)
messagebox.showinfo("成功", f"成功获取邮箱: {email_data['email']}")
except Exception as e:
logger.error(f"测试邮箱API出错: {str(e)}")
messagebox.showerror("错误", f"测试过程中出错: {str(e)}")
self.update_status(test_id, status=f"出错: {str(e)}", result="错误")
finally:
# 恢复按钮状态
self.test_email_button.config(state="normal")
def test_captcha(self):
"""测试PyNoCaptcha验证码"""
"""测试验证码"""
# 验证配置
if not self.captcha_vars["pyno_user_token"].get().strip():
messagebox.showerror("错误", "请先填写PyNoCaptcha API密钥")
messagebox.showerror("错误", "请先填写验证码API密钥")
return
# 保存配置
@@ -404,9 +527,9 @@ class RegistrationGUIWithPynoV2:
threading.Thread(target=self._test_captcha_thread, daemon=True).start()
def _test_captcha_thread(self):
"""在新线程中测试PyNoCaptcha"""
"""在新线程中测试验证码"""
try:
test_id = "测试PyNoCaptcha"
test_id = "测试验证码"
self.update_status(test_id, status="正在准备验证码测试...")
# 首先获取动态sitekey
@@ -481,7 +604,7 @@ class RegistrationGUIWithPynoV2:
except Exception as e:
logger.error(f"测试过程中出错: {str(e)}")
messagebox.showerror("错误", f"测试过程中出错: {str(e)}")
self.update_status("测试PyNoCaptcha", status=f"出错: {str(e)}", result="错误")
self.update_status("测试验证码", status=f"出错: {str(e)}", result="错误")
finally:
# 恢复按钮状态
self.test_captcha_button.config(state="normal")
@@ -547,17 +670,24 @@ class RegistrationGUIWithPynoV2:
messagebox.showerror("错误", f"获取Steam验证信息失败: {str(e)}")
return
# 使用PyNoCaptcha版本的GUIThreadManager
self.manager = GUIThreadManagerWithPyno(
self.config_path,
self.email_path.get(),
self.proxy_path.get(),
self,
completed_tasks
)
# 创建参数字典
manager_params = {
'config_path': self.config_path,
'email_path': self.email_path.get(),
'proxy_path': self.proxy_path.get(),
'gui': self,
'completed_tasks': completed_tasks,
'email_source': self.email_source_var.get(),
'reg_count': int(self.reg_count_var.get()),
'email_api_client': self.email_api_client if self.email_source_var.get() == "api" else None
}
# 使用线程管理器
self.manager = GUIThreadManagerWithPyno(**manager_params)
self.manager.start()
except Exception as e:
logger.error(f"启动注册线程出错: {str(e)}")
messagebox.showerror("错误", str(e))
finally:
self.start_button.config(state="normal")
@@ -572,7 +702,7 @@ class RegistrationGUIWithPynoV2:
if __name__ == "__main__":
root = tk.Tk()
gui = RegistrationGUIWithPynoV2(root)
gui = SteamRegistrationGUI(root)
# 启动时自动刷新Steam信息
threading.Thread(target=gui._refresh_steam_info_thread, daemon=True).start()
root.mainloop()