User: 你好
User: 你好
User: 你好
Assistant: 你好！请问有什么我可以帮忙的吗？
User: import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext
import subprocess
import threading
import itertools
import configparser
import os


class BTCRecoverGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("BTCWallet 恢复工具")

        # 进度配置文件
        self.config_file = "progress.ini"
        self.config = configparser.ConfigParser()
        self.load_progress()  # 加载保存的进度
        self.passwords_list = []  # 存储字典文件中的密码列表

        # 界面框架
        tk.Label(root, text="BTCWallet 恢复工具", font=("Arial", 16)).pack(pady=10)

        # 按钮和日志窗口组件
        self.dat_file_path = tk.StringVar()
        self.dict_file_path = tk.StringVar()
        self.custom_string = tk.StringVar()
        self.phone_prefixes = tk.StringVar()  # 手机号前缀输入框

        self.custom_string_length = tk.StringVar()
        self.custom_chars = tk.StringVar()

        # 添加.dat 文件选择
        dat_frame = tk.Frame(root)
        dat_frame.pack(pady=5)
        tk.Label(dat_frame, text="选择.dat 文件:").pack(side=tk.LEFT)
        tk.Entry(dat_frame, textvariable=self.dat_file_path, state="readonly", width=40).pack(side=tk.LEFT, padx=(5, 0))
        tk.Button(dat_frame, text="浏览", command=self.select_dat_file).pack(side=tk.LEFT)

        # 字典文件选择按钮
        dict_frame = tk.Frame(root)
        dict_frame.pack(pady=5)
        tk.Label(dict_frame, text="选择字典文件:").pack(side=tk.LEFT)
        tk.Entry(dict_frame, textvariable=self.dict_file_path, state="readonly", width=40).pack(side=tk.LEFT, padx=(5, 0))
        self.dict_file_button = tk.Button(dict_frame, text="浏览", command=self.select_dict_file)
        self.dict_file_button.pack(side=tk.LEFT)

        # 手机号前缀输入
        tk.Label(root, text="输入手机号前缀 (使用逗号分隔):").pack()
        tk.Entry(root, textvariable=self.phone_prefixes, width=50).pack(pady=5)

        # 增加单选框功能
        tk.Label(root, text="选择生成密码策略:").pack()
        self.use_phone = tk.BooleanVar(value=False)
        self.use_string = tk.BooleanVar(value=False)

        tk.Checkbutton(root, text="手机号组合 (11位数字)", variable=self.use_phone, command=self.update_dict_state).pack(anchor=tk.W)
        tk.Checkbutton(root, text="自定义字符串", variable=self.use_string, command=self.update_dict_state).pack(anchor=tk.W)

        tk.Entry(root, textvariable=self.custom_string, width=30).pack(pady=5)

        # 自定义字符串长度和字符集
        tk.Label(root, text="自定义字符串长度 (若有效, 只需输入整数):").pack()
        tk.Entry(root, textvariable=self.custom_string_length, width=30).pack(pady=5)

        tk.Label(root, text="自定义字符集:").pack()
        tk.Entry(root, textvariable=self.custom_chars, width=30).pack(pady=5)

        # 字符串位置单选框
        tk.Label(root, text="字符串位置:").pack(pady=5)
        self.string_position = tk.StringVar(value="前面")
        position_frame = tk.Frame(root)
        position_frame.pack()
        tk.Radiobutton(position_frame, text="前面", variable=self.string_position, value="前面").pack(side=tk.LEFT)
        tk.Radiobutton(position_frame, text="中间", variable=self.string_position, value="中间").pack(side=tk.LEFT)
        tk.Radiobutton(position_frame, text="后面", variable=self.string_position, value="后面").pack(side=tk.LEFT)

        # 日志窗口
        tk.Label(root, text="日志窗口").pack(pady=5)
        self.log_window = scrolledtext.ScrolledText(root, width=60, height=6, state="disabled")
        self.log_window.pack(pady=10)

        # 开始和暂停按钮
        self.is_running = False
        self.process_thread = None

        self.start_button = tk.Button(root, text="开始恢复", command=self.start_recover)
        self.start_button.pack(side=tk.LEFT, padx=20)

        self.pause_button = tk.Button(root, text="暂停恢复", state="disabled", command=self.pause_recover)
        self.pause_button.pack(side=tk.RIGHT, padx=20)

        # 日志文件
        self.log_file = "日志.txt"

        # 已尝试密码
        self.tried_passwords = set()
        self.last_password = None  # 记录上一个尝试的密码

    def load_progress(self):
        """加载进度文件"""
        if os.path.exists(self.config_file):
            self.config.read(self.config_file)
            if 'Progress' in self.config:
                # 读取记录的进度
                self.last_password = self.config['Progress'].get('last_password', None)
                tried_passwords = self.config['Progress'].get('tried_passwords', '')
                if tried_passwords:
                    self.tried_passwords = set(tried_passwords.split(','))

    def save_progress(self):
        """保存进度文件"""
        if not self.config.has_section('Progress'):
            self.config.add_section('Progress')
        self.config['Progress']['last_password'] = self.last_password or ''
        self.config['Progress']['tried_passwords'] = ','.join(self.tried_passwords)
        with open(self.config_file, 'w', encoding='utf-8') as configfile:
            self.config.write(configfile)

    def select_dat_file(self):
        file_path = filedialog.askopenfilename(filetypes=[("Wallet Files", "*.dat")])
        if file_path:
            self.dat_file_path.set(file_path)
            self.log_message(f"选择了.dat 文件: {file_path}")

    def select_dict_file(self):
        file_path = filedialog.askopenfilename(filetypes=[("Text Files", "*.txt")])
        if file_path:
            self.dict_file_path.set(file_path)
            self.log_message(f"选择了字典文件: {file_path}")

            # 读取字典文件内容并将其存储在 self.passwords_list 中
            with open(file_path, "r", encoding="utf-8") as file:
                self.passwords_list = [line.strip() for line in file if line.strip()]  # 读取并剔除空行

    def update_dict_state(self):
        if self.use_phone.get() or self.use_string.get():
            self.dict_file_button.config(state="disabled")
            self.dict_file_path.set("")
        else:
            self.dict_file_button.config(state="normal")

    def log_message(self, message):
        self.log_window.config(state="normal")
        self.log_window.insert(tk.END, message + "\n")
        self.log_window.config(state="disabled")
        self.log_window.yview(tk.END)

        with open(self.log_file, "a", encoding="utf-8") as f:
            f.write(message + "\n")
    
    def generate_passwords(self):
        """生成密码时，只跳过已尝试的密码并从中断位置继续"""
        
        # 使用字典文件中的密码组合，生成多行组合
        if self.passwords_list:  # 确保有读取的字典内容
            for r in range(1, len(self.passwords_list) + 1):  # 从1到所有行的组合
                for combination in itertools.combinations(self.passwords_list, r):
                    combined_password = ''.join(combination)  # 将组合的密码行连接为一个字符串
                    if combined_password in self.tried_passwords:
                        continue
                    yield combined_password  # 生成组合的密码

        if self.use_phone.get():
            prefixes = self.phone_prefixes.get().split(",")  # 获取多个前缀
            for prefix in prefixes:
                prefix = prefix.strip()  # 去除多余空格
                # 生成手机号
                for i in range(1000000000):
                    phone_number = f"{prefix}{i:08d}"  # 补零到完整号码
                    if phone_number in self.tried_passwords:
                        continue
                    yield phone_number

        if self.use_string.get():
            base_string = self.custom_string.get()
            custom_length = self.custom_string_length.get()
            custom_chars = self.custom_chars.get()

            if custom_length.isdigit() and 1 <= int(custom_length) <= 10:  # 限制长度范围
                length = int(custom_length)
                # 生成适应大小写的字符串组合
                for variation in itertools.product(*((char.lower(), char.upper()) for char in custom_chars)):
                    for combination in itertools.permutations(variation, length):
                        password = ''.join(combination)
                        if password in self.tried_passwords:
                            continue
                        yield password

            if base_string:
                base_variations = itertools.product(*((char.lower(), char.upper()) for char in base_string))
                for variation in base_variations:
                    password = ''.join(variation)
                    if password in self.tried_passwords:
                        continue
                    yield password

    def start_recover(self):
        if not self.dat_file_path.get():
            messagebox.showerror("错误", "请选择.dat 文件！")
            return

        if not self.is_running:  # 开始新任务
            self.is_running = True
            self.start_button.config(state="disabled")
            self.pause_button.config(state="normal")
            self.process_thread = threading.Thread(target=self.run_btcrecover)
            self.process_thread.start()
        else:  # 如果已经在运行，继续从上次未完成的密码
            self.is_running = True
            self.start_button.config(state="disabled")
            self.pause_button.config(state="normal")

    def run_btcrecover(self):
        try:
            batch_size = 100  # 定义每次处理的密码数量
            passwords_to_try = []  # 存储待尝试的密码列表

            for password in self.generate_passwords():
                if self.last_password and password == self.last_password:
                    continue  # 跳过最后尝试的密码以避免重复
                
                passwords_to_try.append(password)

                if len(passwords_to_try) >= batch_size:
                    self.process_passwords(passwords_to_try)
                    passwords_to_try.clear()  # 清空列表以循环使用

                if not self.is_running:  # 添加这个判断，以便在循环中检查是否需要停止
                    break

            # 处理剩余的密码
            if passwords_to_try:
                self.process_passwords(passwords_to_try)

        except Exception as e:
            self.log_message(f"发生错误：{str(e)}")
        finally:
            self.save_progress()  # 保存当前进度
            self.is_running = False
            self.start_button.config(state="normal")
            self.pause_button.config(state="disabled")

    def process_passwords(self, passwords):
        for password in passwords:
            if not self.is_running:
                self.log_message("恢复任务已暂停！")
                return

            self.log_message(f"尝试密码：{password}")
            command = [
                "python", "btcrecover.py",
                "--wallet", self.dat_file_path.get(),
                "--passwordlist",  # 修改为支持的选项
                "--dsw"  # 添加 --dsw 参数以禁用不必要的输出
            ]

            # 通过标准输入传递密码
            process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)

            # 发送密码到 subprocess
            output, _ = process.communicate(password + "\n")

            for line in output.splitlines():
                if not self.is_running:
                    self.log_message("恢复任务已暂停！")
                    return

                self.log_message(f"输出: {line.strip()}")  # 添加调试信息

                if "password found" in line.lower():
                    self.log_message("密码恢复成功！")  # 确保这个字符串能与外部工具的一致
                    success_message = line.strip()
                    self.log_message(f"成功密码：{success_message}")
                    self.tried_passwords.add(password)  # 记录已尝试的密码
                    self.last_password = password  # 记录成功的密码
                    self.is_running = False  # 找到密码后，将is_running设置为False以停止进程
                    return  # 找到密码后立即返回，停止进一步处理
                elif "password not found" in line.lower():
                    self.log_message(f"密码 {password} 不正确！")
                    self.tried_passwords.add(password)  # 记录已尝试的密码

            self.tried_passwords.add(password)  # 总是添加当前密码到已尝试列表
            self.last_password = password  # 更新最后尝试的密码

    def pause_recover(self):
        if self.is_running:  # 只在运行时才暂停
            self.is_running = False
            self.pause_button.config(state="disabled")
            self.log_message("恢复任务已暂停！")

# 启动程序
if __name__ == "__main__":
    root = tk.Tk()
    app = BTCRecoverGUI(root)
    root.mainloop()
这个代码，可以加快密码尝试速度吗，请展示优化后的代码，谢谢。
Assistant: