|
|
@@ -11,7 +11,6 @@ from datetime import datetime
|
|
|
|
|
|
# 用于存储线程的列表
|
|
|
threads = []
|
|
|
-results = {} # 存储每个模拟器的执行结果
|
|
|
|
|
|
class MuMuEmulatorManager:
|
|
|
# 类级别的剪贴板锁,所有实例共享
|
|
|
@@ -95,6 +94,26 @@ class MuMuEmulatorManager:
|
|
|
result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8')
|
|
|
return result.returncode == 0
|
|
|
|
|
|
+ def clear_app_data(self, index, package_name, log_callback=None):
|
|
|
+ """清除指定应用的数据"""
|
|
|
+ adb_port = self.get_adb_port(index)
|
|
|
+ target_device = f"127.0.0.1:{adb_port}"
|
|
|
+
|
|
|
+ subprocess.run(f"adb connect {target_device}", shell=True, capture_output=True)
|
|
|
+ time.sleep(1)
|
|
|
+
|
|
|
+ cmd = f"adb -s {target_device} shell pm clear {package_name}"
|
|
|
+ result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
|
|
+
|
|
|
+ if "Success" in result.stdout:
|
|
|
+ if log_callback:
|
|
|
+ log_callback(f"✅ 模拟器 {index} 已清除 {package_name} 数据")
|
|
|
+ return True
|
|
|
+ else:
|
|
|
+ if log_callback:
|
|
|
+ log_callback(f"⚠️ 模拟器 {index} 清除数据失败: {result.stdout}")
|
|
|
+ return False
|
|
|
+
|
|
|
def install_apk(self, index, apk_path, log_callback=None):
|
|
|
"""安装APK"""
|
|
|
if not os.path.exists(apk_path):
|
|
|
@@ -376,7 +395,7 @@ class MuMuAutoGUI:
|
|
|
self.load_btn = None
|
|
|
self.start_read_btn = None
|
|
|
self.start_comment_btn = None
|
|
|
-
|
|
|
+ self.results = {}
|
|
|
# 创建界面
|
|
|
self.create_widgets()
|
|
|
|
|
|
@@ -511,7 +530,34 @@ class MuMuAutoGUI:
|
|
|
|
|
|
canvas.pack(side="left", fill="both", expand=True)
|
|
|
scrollbar.pack(side="right", fill="y")
|
|
|
-
|
|
|
+ def select_failed_emulators(self):
|
|
|
+ """选择所有执行失败的模拟器"""
|
|
|
+
|
|
|
+ if not self.results:
|
|
|
+ self.log_message("⚠️ 没有任务执行记录,请先运行任务")
|
|
|
+ return
|
|
|
+
|
|
|
+ failed_indices = [idx for idx, success in self.results.items() if not success]
|
|
|
+
|
|
|
+ if not failed_indices:
|
|
|
+ self.log_message("✅ 没有失败的模拟器")
|
|
|
+ return
|
|
|
+
|
|
|
+ # 清空当前选择
|
|
|
+ for item in self.emulator_tree.get_children():
|
|
|
+ values = self.emulator_tree.item(item, 'values')
|
|
|
+ if values[0] == "☑":
|
|
|
+ self.emulator_tree.item(item, values=("□", values[1], values[2], values[3]))
|
|
|
+
|
|
|
+ # 选中失败的模拟器
|
|
|
+ selected_count = 0
|
|
|
+ for item in self.emulator_tree.get_children():
|
|
|
+ values = self.emulator_tree.item(item, 'values')
|
|
|
+ if values[1] in failed_indices:
|
|
|
+ self.emulator_tree.item(item, values=("☑", values[1], values[2], values[3]))
|
|
|
+ selected_count += 1
|
|
|
+
|
|
|
+ self.log_message(f"✅ 已选中 {selected_count} 个失败模拟器: {', '.join(failed_indices)}")
|
|
|
def create_task_tab(self):
|
|
|
"""创建任务选项卡"""
|
|
|
task_frame = ttk.Frame(self.notebook)
|
|
|
@@ -531,6 +577,10 @@ class MuMuAutoGUI:
|
|
|
# 添加全选按钮
|
|
|
self.select_all_btn = ttk.Button(button_frame, text="全选", command=self.select_all_emulators, width=6)
|
|
|
self.select_all_btn.pack(side='left', padx=5)
|
|
|
+
|
|
|
+ # 添加选择失败项按钮
|
|
|
+ self.select_failed_btn = ttk.Button(button_frame, text="选择失败项", command=self.select_failed_emulators, width=10)
|
|
|
+ self.select_failed_btn.pack(side='left', padx=5)
|
|
|
|
|
|
self.start_read_btn = ttk.Button(button_frame, text="开始阅读", command=self.start_task, width=10)
|
|
|
self.start_read_btn.pack(side='left', padx=10)
|
|
|
@@ -840,7 +890,6 @@ class MuMuAutoGUI:
|
|
|
|
|
|
def run_task(self):
|
|
|
"""执行任务(支持并发,出错直接退出不重试)"""
|
|
|
- global results
|
|
|
global threads
|
|
|
|
|
|
try:
|
|
|
@@ -851,7 +900,6 @@ class MuMuAutoGUI:
|
|
|
self.log_message(f"📌 最大并发数: {max_threads}")
|
|
|
|
|
|
threads = []
|
|
|
- results = {}
|
|
|
|
|
|
def process_emulator(emu):
|
|
|
"""处理单个模拟器的函数,出错直接退出"""
|
|
|
@@ -883,14 +931,14 @@ class MuMuAutoGUI:
|
|
|
self.log_message(f"正在启动模拟器 {index}...")
|
|
|
if not manager.start_emulator(index):
|
|
|
self.log_message(f"❌ 模拟器 {index} 启动失败")
|
|
|
- results[index] = False
|
|
|
+ self.results[index] = False
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "启动失败"))
|
|
|
return
|
|
|
|
|
|
# 等待就绪
|
|
|
if not manager.wait_for_emulator_ready(index, timeout=180, log_callback=self.log_message):
|
|
|
self.log_message(f"❌ 模拟器 {index} 启动超时")
|
|
|
- results[index] = False
|
|
|
+ self.results[index] = False
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "启动超时"))
|
|
|
return
|
|
|
|
|
|
@@ -898,7 +946,7 @@ class MuMuAutoGUI:
|
|
|
if not manager.check_resolution(index, 720, self.log_message):
|
|
|
self.log_message(f"❌ 模拟器 {index} 分辨率不是720,停止任务并关闭模拟器")
|
|
|
manager.stop_emulator(index)
|
|
|
- results[index] = False
|
|
|
+ self.results[index] = False
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "分辨率错误"))
|
|
|
return
|
|
|
|
|
|
@@ -957,7 +1005,7 @@ class MuMuAutoGUI:
|
|
|
if errNumber > 30:
|
|
|
self.log_message(f"模拟器 {index} 连续多次未进入主界面,退出...")
|
|
|
manager.stop_emulator(index)
|
|
|
- results[index] = False
|
|
|
+ self.results[index] = False
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "进入主界面失败"))
|
|
|
return
|
|
|
|
|
|
@@ -966,7 +1014,7 @@ class MuMuAutoGUI:
|
|
|
|
|
|
# 执行打开书籍
|
|
|
if not self.openBook(manager, index):
|
|
|
- results[index] = False
|
|
|
+ self.results[index] = False
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "打开书籍失败"))
|
|
|
return
|
|
|
|
|
|
@@ -1006,7 +1054,7 @@ class MuMuAutoGUI:
|
|
|
if errNumber > 10:
|
|
|
self.log_message(f"模拟器 {index} 连续多次未检测到目录界面,退出...")
|
|
|
manager.stop_emulator(index)
|
|
|
- results[index] = False
|
|
|
+ self.results[index] = False
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "翻页失败"))
|
|
|
return
|
|
|
|
|
|
@@ -1039,18 +1087,23 @@ class MuMuAutoGUI:
|
|
|
time.sleep(2)
|
|
|
manager.tap(index, 255, 84, self.log_message)
|
|
|
time.sleep(3)
|
|
|
+
|
|
|
+ # 清除应用数据
|
|
|
+ self.log_message(f"正在清除模拟器 {index} 应用数据...")
|
|
|
+ manager.clear_app_data(index, self.package_name_var.get(), self.log_message)
|
|
|
+ time.sleep(2)
|
|
|
|
|
|
# 关闭模拟器
|
|
|
self.log_message(f"正在关闭模拟器 {index}...")
|
|
|
manager.stop_emulator(index)
|
|
|
|
|
|
self.log_message(f"✅ 模拟器 {index} 任务完成")
|
|
|
- results[index] = True
|
|
|
+ self.results[index] = True
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "任务完成"))
|
|
|
|
|
|
except Exception as e:
|
|
|
self.log_message(f"❌ 模拟器 {index} 执行出错: {e}")
|
|
|
- results[index] = False
|
|
|
+ self.results[index] = False
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "执行出错"))
|
|
|
finally:
|
|
|
# 减少活跃线程计数
|
|
|
@@ -1076,7 +1129,7 @@ class MuMuAutoGUI:
|
|
|
for thread in threads:
|
|
|
thread.join()
|
|
|
|
|
|
- success_count = sum(1 for v in results.values() if v)
|
|
|
+ success_count = sum(1 for v in self.results.values() if v)
|
|
|
self.log_message(f"\n🎉 任务执行完毕!成功: {success_count}/{len(self.selected_emulators)}")
|
|
|
|
|
|
except Exception as e:
|
|
|
@@ -1100,7 +1153,6 @@ class MuMuAutoGUI:
|
|
|
self.log_message(f"📌 最大并发数: {max_threads}")
|
|
|
|
|
|
threads = []
|
|
|
- results = {}
|
|
|
|
|
|
def process_emulator(emu):
|
|
|
"""处理单个模拟器的函数,出错直接退出"""
|
|
|
@@ -1132,14 +1184,14 @@ class MuMuAutoGUI:
|
|
|
self.log_message(f"正在启动模拟器 {index}...")
|
|
|
if not manager.start_emulator(index):
|
|
|
self.log_message(f"❌ 模拟器 {index} 启动失败")
|
|
|
- results[index] = False
|
|
|
+ self.results[index] = False
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "启动失败"))
|
|
|
return
|
|
|
|
|
|
# 等待就绪
|
|
|
if not manager.wait_for_emulator_ready(index, timeout=180, log_callback=self.log_message):
|
|
|
self.log_message(f"❌ 模拟器 {index} 启动超时")
|
|
|
- results[index] = False
|
|
|
+ self.results[index] = False
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "启动超时"))
|
|
|
return
|
|
|
|
|
|
@@ -1147,7 +1199,7 @@ class MuMuAutoGUI:
|
|
|
if not manager.check_resolution(index, 720, self.log_message):
|
|
|
self.log_message(f"❌ 模拟器 {index} 分辨率不是720,停止任务并关闭模拟器")
|
|
|
manager.stop_emulator(index)
|
|
|
- results[index] = False
|
|
|
+ self.results[index] = False
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "分辨率错误"))
|
|
|
return
|
|
|
|
|
|
@@ -1190,7 +1242,7 @@ class MuMuAutoGUI:
|
|
|
if errNumber > 30:
|
|
|
self.log_message(f"模拟器 {index} 连续多次未进入主界面,退出...")
|
|
|
manager.stop_emulator(index)
|
|
|
- results[index] = False
|
|
|
+ self.results[index] = False
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "进入主界面失败"))
|
|
|
return
|
|
|
|
|
|
@@ -1199,7 +1251,7 @@ class MuMuAutoGUI:
|
|
|
|
|
|
# 执行打开书籍
|
|
|
if not self.openBook(manager, index):
|
|
|
- results[index] = False
|
|
|
+ self.results[index] = False
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "打开书籍失败"))
|
|
|
return
|
|
|
|
|
|
@@ -1214,18 +1266,23 @@ class MuMuAutoGUI:
|
|
|
manager.tap(index, 640, 95, self.log_message)
|
|
|
|
|
|
time.sleep(4)
|
|
|
+
|
|
|
+ # 清除应用数据
|
|
|
+ self.log_message(f"正在清除模拟器 {index} 应用数据...")
|
|
|
+ manager.clear_app_data(index, self.package_name_var.get(), self.log_message)
|
|
|
+ time.sleep(2)
|
|
|
|
|
|
# 关闭模拟器
|
|
|
self.log_message(f"正在关闭模拟器 {index}...")
|
|
|
manager.stop_emulator(index)
|
|
|
|
|
|
self.log_message(f"✅ 模拟器 {index} 任务完成")
|
|
|
- results[index] = True
|
|
|
+ self.results[index] = True
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "任务完成"))
|
|
|
|
|
|
except Exception as e:
|
|
|
self.log_message(f"❌ 模拟器 {index} 执行出错: {e}")
|
|
|
- results[index] = False
|
|
|
+ self.results[index] = False
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "执行出错"))
|
|
|
finally:
|
|
|
# 减少活跃线程计数
|
|
|
@@ -1250,7 +1307,7 @@ class MuMuAutoGUI:
|
|
|
for thread in threads:
|
|
|
thread.join()
|
|
|
|
|
|
- success_count = sum(1 for v in results.values() if v)
|
|
|
+ success_count = sum(1 for v in self.results.values() if v)
|
|
|
self.log_message(f"\n🎉 任务执行完毕!成功: {success_count}/{len(self.selected_emulators)}")
|
|
|
|
|
|
except Exception as e:
|