实现邮箱API集成和注册数量限制功能
This commit is contained in:
@@ -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()
|
||||
Reference in New Issue
Block a user