|
|
@@ -370,6 +370,8 @@ class MuMuAutoGUI:
|
|
|
|
|
|
self.selected_emulators = []
|
|
|
self.thread_semaphore = None # 添加信号量控制并发数
|
|
|
+ self.active_threads = 0 # 记录当前活跃线程数
|
|
|
+ self.threads_lock = threading.Lock() # 线程锁
|
|
|
|
|
|
self.load_btn = None
|
|
|
self.start_read_btn = None
|
|
|
@@ -736,36 +738,34 @@ class MuMuAutoGUI:
|
|
|
self.log_message("⏹ 正在停止任务...")
|
|
|
|
|
|
def openBook(self, manager, index):
|
|
|
- global results
|
|
|
+ """打开书籍,遇到错误返回False"""
|
|
|
# 执行操作
|
|
|
manager.tap(index, 390, 90, self.log_message)
|
|
|
- color56065 = manager.get_pixel_color(index, 560, 65, log_callback=self.log_message)
|
|
|
errNumber = 0
|
|
|
- while color56065 != "#F7F7F7":
|
|
|
- if color56065 == "#EBF8EC":
|
|
|
+ while True:
|
|
|
+ color56065 = manager.get_pixel_color(index, 560, 65, log_callback=self.log_message)
|
|
|
+ if color56065 == "#F7F7F7":
|
|
|
+ break
|
|
|
+ elif color56065 == "#EBF8EC":
|
|
|
manager.tap(index, 390, 90, self.log_message)
|
|
|
self.log_message(f"模拟器 {index} 尝试重新点击搜索...")
|
|
|
- if color56065 == "#5E635E":
|
|
|
+ elif color56065 == "#5E635E":
|
|
|
self.log_message(f"模拟器 {index} 需要关闭红包弹窗...")
|
|
|
manager.tap(index, 640, 260, self.log_message)
|
|
|
time.sleep(20)
|
|
|
manager.tap(index, 57, 193, self.log_message)
|
|
|
- if color56065 in ["#EBE8E4", "#CDD0D1"]:
|
|
|
+ elif color56065 in ["#EBE8E4", "#CDD0D1"]:
|
|
|
self.log_message(f"模拟器 {index} 进入错误页面,返回...")
|
|
|
manager.tap(index, 44, 92, self.log_message)
|
|
|
else:
|
|
|
errNumber = errNumber + 1
|
|
|
if errNumber > 30:
|
|
|
self.log_message(f"模拟器 {index} 连续多次未检测到搜索页面,设置错误并退出...")
|
|
|
- # 关闭模拟器
|
|
|
- self.log_message(f"正在关闭模拟器 {index}...")
|
|
|
manager.stop_emulator(index)
|
|
|
- results[index] = False
|
|
|
- self.log_message(f"✅ 模拟器 {index} 错误退出")
|
|
|
- self.root.after(0, lambda: self.update_emulator_status(index, "遇到错误"))
|
|
|
+ return False
|
|
|
self.log_message(f"模拟器 {index} 等待搜索页面准备就绪...")
|
|
|
time.sleep(3)
|
|
|
- color56065 = manager.get_pixel_color(index, 560, 65, log_callback=self.log_message)
|
|
|
+
|
|
|
time.sleep(3)
|
|
|
# 点输入框
|
|
|
manager.tap(index, 340, 90, self.log_message)
|
|
|
@@ -773,17 +773,16 @@ class MuMuAutoGUI:
|
|
|
# 黏贴
|
|
|
manager.paste_text(index, self.search_content_var.get(), self.log_message)
|
|
|
time.sleep(3)
|
|
|
+
|
|
|
errNumber = 0
|
|
|
- while manager.get_pixel_color(index, 435, 880, log_callback=self.log_message) != "#FFFFFF":
|
|
|
+ while True:
|
|
|
+ if manager.get_pixel_color(index, 435, 880, log_callback=self.log_message) == "#FFFFFF":
|
|
|
+ break
|
|
|
errNumber = errNumber + 1
|
|
|
if errNumber > 30:
|
|
|
self.log_message(f"模拟器 {index} 连续多次未检测到搜索页面,设置错误并退出...")
|
|
|
- # 关闭模拟器
|
|
|
- self.log_message(f"正在关闭模拟器 {index}...")
|
|
|
manager.stop_emulator(index)
|
|
|
- results[index] = False
|
|
|
- self.log_message(f"✅ 模拟器 {index} 错误退出")
|
|
|
- self.root.after(0, lambda: self.update_emulator_status(index, "遇到错误"))
|
|
|
+ return False
|
|
|
self.log_message(f"模拟器 {index} 没有输入搜索内容...")
|
|
|
# 点输入框
|
|
|
manager.tap(index, 556, 87, self.log_message)
|
|
|
@@ -793,13 +792,13 @@ class MuMuAutoGUI:
|
|
|
# 黏贴
|
|
|
manager.paste_text(index, self.search_content_var.get(), self.log_message)
|
|
|
time.sleep(3)
|
|
|
+
|
|
|
manager.tap(index, 655, 92, self.log_message)
|
|
|
time.sleep(6)
|
|
|
|
|
|
+ errNumber = 0
|
|
|
while True:
|
|
|
color630235 = manager.get_pixel_color(index, 630, 235, log_callback=self.log_message)
|
|
|
- print(color630235)
|
|
|
- errNumber = 0
|
|
|
if color630235 in ["#FFFFFF"]:
|
|
|
self.log_message(f"模拟器 {index} 已经在搜索结果页面,继续...")
|
|
|
break
|
|
|
@@ -813,12 +812,8 @@ class MuMuAutoGUI:
|
|
|
errNumber = errNumber + 1
|
|
|
if errNumber > 30:
|
|
|
self.log_message(f"模拟器 {index} 连续多次未检测到搜索页面,设置错误并退出...")
|
|
|
- # 关闭模拟器
|
|
|
- self.log_message(f"正在关闭模拟器 {index}...")
|
|
|
manager.stop_emulator(index)
|
|
|
- results[index] = False
|
|
|
- self.log_message(f"✅ 模拟器 {index} 错误退出")
|
|
|
- self.root.after(0, lambda: self.update_emulator_status(index, "遇到错误"))
|
|
|
+ return False
|
|
|
self.log_message(f"模拟器 {index} 等待搜索结果...")
|
|
|
time.sleep(3)
|
|
|
|
|
|
@@ -826,48 +821,55 @@ class MuMuAutoGUI:
|
|
|
time.sleep(6)
|
|
|
manager.tap(index, 355, 333, self.log_message)
|
|
|
time.sleep(5)
|
|
|
+
|
|
|
errNumber = 0
|
|
|
while True:
|
|
|
color630235 = manager.get_pixel_color(index, 630, 235, log_callback=self.log_message)
|
|
|
- print(color630235)
|
|
|
if color630235 in ["#E8E3CE", "#E0DBC6", "#CCCBCB", "#DFDAC5", "#141000", "#E3DEC9"]:
|
|
|
self.log_message(f"模拟器 {index} 已经在看书目录界面,继续...")
|
|
|
- break
|
|
|
+ return True
|
|
|
else:
|
|
|
errNumber = errNumber + 1
|
|
|
if errNumber > 20:
|
|
|
self.log_message(f"模拟器 {index} 连续多次未检测到搜索页面,设置错误并退出...")
|
|
|
- # 关闭模拟器
|
|
|
- self.log_message(f"正在关闭模拟器 {index}...")
|
|
|
manager.stop_emulator(index)
|
|
|
- results[index] = False
|
|
|
- self.log_message(f"✅ 模拟器 {index} 错误退出")
|
|
|
- self.root.after(0, lambda: self.update_emulator_status(index, "遇到错误"))
|
|
|
+ return False
|
|
|
self.log_message(f"模拟器 {index} 还在搜索结果页面,重新点击...")
|
|
|
manager.tap(index, 355, 333, self.log_message)
|
|
|
time.sleep(5)
|
|
|
|
|
|
def run_task(self):
|
|
|
+ """执行任务(支持并发,出错直接退出不重试)"""
|
|
|
global results
|
|
|
global threads
|
|
|
- """执行任务(支持并发)"""
|
|
|
+
|
|
|
try:
|
|
|
- manager = MuMuEmulatorManager(self.mumu_path_var.get())
|
|
|
-
|
|
|
# 获取最大线程数
|
|
|
max_threads = int(self.max_threads_var.get()) if self.max_threads_var.get().isdigit() else 1
|
|
|
self.thread_semaphore = threading.Semaphore(max_threads)
|
|
|
+ self.active_threads = 0
|
|
|
self.log_message(f"📌 最大并发数: {max_threads}")
|
|
|
|
|
|
-
|
|
|
+ threads = []
|
|
|
+ results = {}
|
|
|
|
|
|
def process_emulator(emu):
|
|
|
- """处理单个模拟器的函数"""
|
|
|
- with self.thread_semaphore:
|
|
|
+ """处理单个模拟器的函数,出错直接退出"""
|
|
|
+ # 获取信号量,控制并发数
|
|
|
+ self.thread_semaphore.acquire()
|
|
|
+
|
|
|
+ # 增加活跃线程计数
|
|
|
+ with self.threads_lock:
|
|
|
+ self.active_threads += 1
|
|
|
+ current_active = self.active_threads
|
|
|
+ self.log_message(f"📊 当前活跃线程数: {current_active}/{max_threads}")
|
|
|
+
|
|
|
+ index = emu['index']
|
|
|
+
|
|
|
+ try:
|
|
|
if self.should_stop:
|
|
|
return
|
|
|
|
|
|
- index = emu['index']
|
|
|
self.log_message(f"\n{'='*50}")
|
|
|
self.log_message(f"开始处理模拟器 {index} ({emu['name']})")
|
|
|
self.log_message(f"{'='*50}")
|
|
|
@@ -875,157 +877,200 @@ class MuMuAutoGUI:
|
|
|
# 更新状态为运行中
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "运行中"))
|
|
|
|
|
|
- try:
|
|
|
- # 启动模拟器
|
|
|
- self.log_message(f"正在启动模拟器 {index}...")
|
|
|
- if not manager.start_emulator(index):
|
|
|
- self.log_message(f"❌ 模拟器 {index} 启动失败")
|
|
|
- results[index] = False
|
|
|
- return
|
|
|
-
|
|
|
- # 等待就绪
|
|
|
- if not manager.wait_for_emulator_ready(index, timeout=180, log_callback=self.log_message):
|
|
|
- self.log_message(f"❌ 模拟器 {index} 启动超时")
|
|
|
- results[index] = False
|
|
|
- return
|
|
|
-
|
|
|
+ manager = MuMuEmulatorManager(self.mumu_path_var.get())
|
|
|
+
|
|
|
+ # 启动模拟器
|
|
|
+ self.log_message(f"正在启动模拟器 {index}...")
|
|
|
+ if not manager.start_emulator(index):
|
|
|
+ self.log_message(f"❌ 模拟器 {index} 启动失败")
|
|
|
+ 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.root.after(0, lambda: self.update_emulator_status(index, "启动超时"))
|
|
|
+ return
|
|
|
+
|
|
|
+ time.sleep(5)
|
|
|
+ if not manager.check_resolution(index, 720, self.log_message):
|
|
|
+ self.log_message(f"❌ 模拟器 {index} 分辨率不是720,停止任务并关闭模拟器")
|
|
|
+ manager.stop_emulator(index)
|
|
|
+ results[index] = False
|
|
|
+ self.root.after(0, lambda: self.update_emulator_status(index, "分辨率错误"))
|
|
|
+ return
|
|
|
+
|
|
|
+ # 安装APK
|
|
|
+ if not manager.install_apk(index, self.apk_path_var.get(), self.log_message):
|
|
|
+ self.log_message(f"⚠️ APK安装失败,但继续执行...")
|
|
|
+
|
|
|
+ # 打开应用
|
|
|
+ manager.open_app(index, self.package_name_var.get(), self.log_message)
|
|
|
+
|
|
|
+ # 判断是否需要同意
|
|
|
+ time.sleep(20)
|
|
|
+ button_color = manager.get_pixel_color(index, 394, 846, log_callback=self.log_message)
|
|
|
+
|
|
|
+ # 是否是第一次进入
|
|
|
+ if button_color and button_color.upper() == "#FC7838":
|
|
|
+ manager.tap(index, 394, 846, self.log_message)
|
|
|
+ time.sleep(120)
|
|
|
+ manager.tap(index, 640, 260, self.log_message)
|
|
|
+ time.sleep(20)
|
|
|
+ manager.tap(index, 57, 193, self.log_message)
|
|
|
time.sleep(5)
|
|
|
- if not manager.check_resolution(index, 720, self.log_message):
|
|
|
- self.log_message(f"❌ 模拟器 {index} 分辨率不是720,停止任务并关闭模拟器")
|
|
|
- manager.stop_emulator(index)
|
|
|
- results[index] = False
|
|
|
- self.root.after(0, lambda: self.update_emulator_status(index, "分辨率错误"))
|
|
|
- return
|
|
|
- # 安装APK
|
|
|
- if not manager.install_apk(index, self.apk_path_var.get(), self.log_message):
|
|
|
- self.log_message(f"❌ APK安装失败")
|
|
|
- # results[index] = False
|
|
|
- # return
|
|
|
+ else:
|
|
|
+ time.sleep(10)
|
|
|
+
|
|
|
+ # 等待进入主界面
|
|
|
+ errNumber = 0
|
|
|
+ while True:
|
|
|
+ if self.should_stop or self.is_paused:
|
|
|
+ # 处理暂停
|
|
|
+ while self.is_paused and not self.should_stop:
|
|
|
+ time.sleep(1)
|
|
|
+ if self.should_stop:
|
|
|
+ return
|
|
|
|
|
|
- # 打开应用
|
|
|
- manager.open_app(index, self.package_name_var.get(), self.log_message)
|
|
|
- # 判断是否需要同意
|
|
|
- time.sleep(20)
|
|
|
- button_color = manager.get_pixel_color(index, 394, 846, log_callback=self.log_message)
|
|
|
- self.log_message(button_color)
|
|
|
- # 是否是第一次进入
|
|
|
- if (button_color and button_color.upper() == "#FC7838"):
|
|
|
- manager.tap(index, 394, 846, self.log_message)
|
|
|
- time.sleep(120)
|
|
|
- boxColor = manager.get_pixel_color(index, 640, 260, log_callback=self.log_message)
|
|
|
+ color560130 = manager.get_pixel_color(index, 560, 130, log_callback=self.log_message)
|
|
|
+
|
|
|
+ if color560130 in ["#EEF8EE", "#F7F7F7"]:
|
|
|
+ self.log_message(f"模拟器 {index} 已经进入主界面,继续...")
|
|
|
+ break
|
|
|
+ elif color560130 in ["#5F635F"]:
|
|
|
+ self.log_message(f"模拟器 {index} 需要关闭红包弹窗...")
|
|
|
manager.tap(index, 640, 260, self.log_message)
|
|
|
time.sleep(20)
|
|
|
-
|
|
|
manager.tap(index, 57, 193, self.log_message)
|
|
|
- time.sleep(5)
|
|
|
+ elif color560130 in ["#CED0D2"]:
|
|
|
+ self.log_message(f"模拟器 {index} 需要关闭广告弹窗...")
|
|
|
+ manager.tap(index, 200, 80, self.log_message)
|
|
|
+ elif color560130 in ["#F3CEA9"]:
|
|
|
+ self.log_message(f"模拟器 {index} 进入错误页面,返回...")
|
|
|
+ manager.tap(index, 44, 92, self.log_message)
|
|
|
+ time.sleep(20)
|
|
|
+ manager.tap(index, 57, 193, self.log_message)
|
|
|
else:
|
|
|
- time.sleep(10)
|
|
|
-
|
|
|
- while True:
|
|
|
- color560130 = manager.get_pixel_color(index, 560, 130, log_callback=self.log_message)
|
|
|
- if color560130 in ["#EEF8EE", "#F7F7F7"]:
|
|
|
- self.log_message(f"模拟器 {index} 已经进入主界面,继续...")
|
|
|
- break
|
|
|
- if color560130 in ["#5F635F"]:
|
|
|
- self.log_message(f"模拟器 {index} 需要关闭红包弹窗...")
|
|
|
- manager.tap(index, 640, 260, self.log_message)
|
|
|
- time.sleep(20)
|
|
|
-
|
|
|
- manager.tap(index, 57, 193, self.log_message)
|
|
|
- if color560130 in ["#CED0D2"]:
|
|
|
- self.log_message(f"模拟器 {index} 需要关闭广告弹窗...")
|
|
|
- manager.tap(index, 200, 80, self.log_message)
|
|
|
-
|
|
|
- # F3CEA9可能是推荐榜
|
|
|
- if color560130 in ["#F3CEA9"]:
|
|
|
- self.log_message(f"模拟器 {index} 进入错误页面,返回...")
|
|
|
- manager.tap(index, 44, 92, self.log_message)
|
|
|
- time.sleep(20)
|
|
|
-
|
|
|
- manager.tap(index, 57, 193, self.log_message)
|
|
|
- self.log_message(f"模拟器 {index} 等待进入主界面中...")
|
|
|
- # manager.get_pixel_color(index, 640, 260, log_callback=self.log_message)
|
|
|
- time.sleep(5)
|
|
|
- # 执行操作
|
|
|
- self.openBook(manager, index)
|
|
|
+ errNumber = errNumber + 1
|
|
|
+ if errNumber > 30:
|
|
|
+ self.log_message(f"模拟器 {index} 连续多次未进入主界面,退出...")
|
|
|
+ manager.stop_emulator(index)
|
|
|
+ results[index] = False
|
|
|
+ self.root.after(0, lambda: self.update_emulator_status(index, "进入主界面失败"))
|
|
|
+ return
|
|
|
|
|
|
+ self.log_message(f"模拟器 {index} 等待进入主界面中...")
|
|
|
+ time.sleep(5)
|
|
|
+
|
|
|
+ # 执行打开书籍
|
|
|
+ if not self.openBook(manager, index):
|
|
|
+ results[index] = False
|
|
|
+ self.root.after(0, lambda: self.update_emulator_status(index, "打开书籍失败"))
|
|
|
+ return
|
|
|
+
|
|
|
+ time.sleep(8)
|
|
|
+
|
|
|
+ # 翻页
|
|
|
+ page_range = self.page_count_var.get()
|
|
|
+ if '-' in page_range:
|
|
|
+ parts = page_range.split('-')
|
|
|
+ if len(parts) == 2 and parts[0].isdigit() and parts[1].isdigit():
|
|
|
+ page_count = random.randint(int(parts[0]), int(parts[1]))
|
|
|
+ else:
|
|
|
+ page_count = 10
|
|
|
+ else:
|
|
|
+ page_count = int(page_range) if page_range.isdigit() else 10
|
|
|
+
|
|
|
+ for page in range(page_count):
|
|
|
+ if self.should_stop or self.is_paused:
|
|
|
+ # 处理暂停
|
|
|
+ while self.is_paused and not self.should_stop:
|
|
|
+ time.sleep(1)
|
|
|
+ if self.should_stop:
|
|
|
+ return
|
|
|
|
|
|
- time.sleep(8)
|
|
|
+ # 判断是否在看书目录界面
|
|
|
errNumber = 0
|
|
|
- # 翻页
|
|
|
- for page in range(int(self.page_count_var.get()) if self.page_count_var.get().isdigit() else 5):
|
|
|
- # 判断是否在看书目录界面
|
|
|
- while True:
|
|
|
- color7001000 = manager.get_pixel_color(index, 700, 1000, log_callback=self.log_message)
|
|
|
- if color7001000 in ["#E8E3CE", "#E0DBC6", "#CCCBCB"]:
|
|
|
- self.log_message(f"模拟器 {index} 在看书目录界面,继续翻页...")
|
|
|
- break
|
|
|
- if color7001000 in [ "#F9F9FC"]:
|
|
|
- self.log_message(f"模拟器 {index} 遇到广告,点击跳过...")
|
|
|
- manager.tap(index, 700, 300, self.log_message)
|
|
|
- self.log_message(f"模拟器 {index} 不在看书目录界面,等待中...")
|
|
|
+ while True:
|
|
|
+ color7001000 = manager.get_pixel_color(index, 700, 1000, log_callback=self.log_message)
|
|
|
+ if color7001000 in ["#E8E3CE", "#E0DBC6", "#CCCBCB"]:
|
|
|
+ self.log_message(f"模拟器 {index} 在看书目录界面,继续翻页...")
|
|
|
+ break
|
|
|
+ elif color7001000 in ["#F9F9FC"]:
|
|
|
+ self.log_message(f"模拟器 {index} 遇到广告,点击跳过...")
|
|
|
+ manager.tap(index, 700, 300, self.log_message)
|
|
|
+ else:
|
|
|
errNumber = errNumber + 1
|
|
|
if errNumber > 10:
|
|
|
- self.log_message(f"模拟器 {index} 连续多次未检测到目录界面,设置错误并退出...")
|
|
|
- # 关闭模拟器
|
|
|
- self.log_message(f"正在关闭模拟器 {index}...")
|
|
|
+ self.log_message(f"模拟器 {index} 连续多次未检测到目录界面,退出...")
|
|
|
manager.stop_emulator(index)
|
|
|
-
|
|
|
- self.log_message(f"✅ 模拟器 {index} 错误退出")
|
|
|
results[index] = False
|
|
|
- self.root.after(0, lambda: self.update_emulator_status(index, "遇到错误"))
|
|
|
- # 判断是否有广告
|
|
|
- time.sleep(2)
|
|
|
- if manager.get_pixel_color(index, 700, 1200, log_callback=self.log_message) in ["#E8E3CE"]:
|
|
|
- self.log_message(f"模拟器 {index} 点击跳过广告!")
|
|
|
- manager.tap(index, 700, 1200, self.log_message)
|
|
|
- time.sleep(3)
|
|
|
- if self.should_stop or self.is_paused:
|
|
|
- break
|
|
|
- intervalNum = 30
|
|
|
- if ('-' in self.page_interval_var.get()):
|
|
|
- parts = self.page_interval_var.get().split('-')
|
|
|
- if len(parts) == 2 and parts[0].isdigit() and parts[1].isdigit():
|
|
|
- min_interval = int(parts[0])
|
|
|
- max_interval = int(parts[1])
|
|
|
- intervalNum = random.randint(min_interval, max_interval)
|
|
|
+ self.root.after(0, lambda: self.update_emulator_status(index, "翻页失败"))
|
|
|
+ return
|
|
|
+
|
|
|
+ # 判断是否有广告
|
|
|
+ if manager.get_pixel_color(index, 700, 1200, log_callback=self.log_message) in ["#E8E3CE"]:
|
|
|
+ self.log_message(f"模拟器 {index} 点击跳过广告!")
|
|
|
+ manager.tap(index, 700, 1200, self.log_message)
|
|
|
+
|
|
|
+ time.sleep(2)
|
|
|
+
|
|
|
+ # 随机翻页间隔
|
|
|
+ interval_str = self.page_interval_var.get()
|
|
|
+ if '-' in interval_str:
|
|
|
+ parts = interval_str.split('-')
|
|
|
+ if len(parts) == 2 and parts[0].isdigit() and parts[1].isdigit():
|
|
|
+ intervalNum = random.randint(int(parts[0]), int(parts[1]))
|
|
|
else:
|
|
|
- intervalNum = int(self.page_interval_var.get()) if self.page_interval_var.get().isdigit() else 30
|
|
|
- time.sleep(intervalNum)
|
|
|
- # manager.tap(index, 700, 1055, self.log_message)
|
|
|
- # 清空错误信息
|
|
|
- errNumber = 0
|
|
|
- # manager.tap(index, 700, 1000, self.log_message)
|
|
|
- manager.swipe(index, 700, 700, 200, 700, 500, self.log_message)
|
|
|
- time.sleep(2)
|
|
|
- # 加入书签
|
|
|
- self.log_message(f"正在加入书架 {index}...")
|
|
|
- manager.tap(index, 360, 600, self.log_message)
|
|
|
- time.sleep(2)
|
|
|
- manager.tap(index, 255, 84, self.log_message)
|
|
|
- time.sleep(3)
|
|
|
- # 关闭模拟器
|
|
|
- self.log_message(f"正在关闭模拟器 {index}...")
|
|
|
- manager.stop_emulator(index)
|
|
|
+ intervalNum = 30
|
|
|
+ else:
|
|
|
+ intervalNum = int(interval_str) if interval_str.isdigit() else 30
|
|
|
|
|
|
- self.log_message(f"✅ 模拟器 {index} 任务完成")
|
|
|
- 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.root.after(0, lambda: self.update_emulator_status(index, "执行出错"))
|
|
|
+ time.sleep(intervalNum)
|
|
|
+ manager.swipe(index, 700, 700, 200, 700, 500, self.log_message)
|
|
|
+
|
|
|
+ time.sleep(2)
|
|
|
+
|
|
|
+ # 加入书签
|
|
|
+ self.log_message(f"正在加入书架 {index}...")
|
|
|
+ manager.tap(index, 360, 600, self.log_message)
|
|
|
+ time.sleep(2)
|
|
|
+ manager.tap(index, 255, 84, self.log_message)
|
|
|
+ time.sleep(3)
|
|
|
+
|
|
|
+ # 关闭模拟器
|
|
|
+ self.log_message(f"正在关闭模拟器 {index}...")
|
|
|
+ manager.stop_emulator(index)
|
|
|
+
|
|
|
+ self.log_message(f"✅ 模拟器 {index} 任务完成")
|
|
|
+ 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.root.after(0, lambda: self.update_emulator_status(index, "执行出错"))
|
|
|
+ finally:
|
|
|
+ # 减少活跃线程计数
|
|
|
+ with self.threads_lock:
|
|
|
+ self.active_threads -= 1
|
|
|
+ current_active = self.active_threads
|
|
|
+ self.log_message(f"📊 当前活跃线程数: {current_active}/{max_threads}")
|
|
|
+
|
|
|
+ # 释放信号量,让下一个等待的线程开始
|
|
|
+ self.thread_semaphore.release()
|
|
|
|
|
|
# 启动所有模拟器任务(信号量会自动控制并发数)
|
|
|
for emu in self.selected_emulators:
|
|
|
if self.should_stop:
|
|
|
break
|
|
|
- # 等待直到有空闲槽位(信号量内部处理)
|
|
|
thread = threading.Thread(target=process_emulator, args=(emu,))
|
|
|
thread.start()
|
|
|
threads.append(thread)
|
|
|
# 稍微延迟一下,避免同时启动太多
|
|
|
- time.sleep(10)
|
|
|
+ time.sleep(2)
|
|
|
|
|
|
# 等待所有线程完成
|
|
|
for thread in threads:
|
|
|
@@ -1046,26 +1091,34 @@ class MuMuAutoGUI:
|
|
|
|
|
|
|
|
|
def run_task2(self):
|
|
|
- """执行评价任务(支持并发)"""
|
|
|
+ """执行评价任务(支持并发,出错直接退出不重试)"""
|
|
|
try:
|
|
|
- manager = MuMuEmulatorManager(self.mumu_path_var.get())
|
|
|
-
|
|
|
# 获取最大线程数
|
|
|
max_threads = int(self.max_threads_var.get()) if self.max_threads_var.get().isdigit() else 1
|
|
|
self.thread_semaphore = threading.Semaphore(max_threads)
|
|
|
+ self.active_threads = 0
|
|
|
self.log_message(f"📌 最大并发数: {max_threads}")
|
|
|
|
|
|
- # 用于存储线程的列表
|
|
|
threads = []
|
|
|
results = {}
|
|
|
|
|
|
def process_emulator(emu):
|
|
|
- """处理单个模拟器的函数"""
|
|
|
- with self.thread_semaphore:
|
|
|
+ """处理单个模拟器的函数,出错直接退出"""
|
|
|
+ # 获取信号量,控制并发数
|
|
|
+ self.thread_semaphore.acquire()
|
|
|
+
|
|
|
+ # 增加活跃线程计数
|
|
|
+ with self.threads_lock:
|
|
|
+ self.active_threads += 1
|
|
|
+ current_active = self.active_threads
|
|
|
+ self.log_message(f"📊 当前活跃线程数: {current_active}/{max_threads}")
|
|
|
+
|
|
|
+ index = emu['index']
|
|
|
+
|
|
|
+ try:
|
|
|
if self.should_stop:
|
|
|
return
|
|
|
|
|
|
- index = emu['index']
|
|
|
self.log_message(f"\n{'='*50}")
|
|
|
self.log_message(f"开始处理模拟器 {index} ({emu['name']})")
|
|
|
self.log_message(f"{'='*50}")
|
|
|
@@ -1073,64 +1126,116 @@ class MuMuAutoGUI:
|
|
|
# 更新状态为运行中
|
|
|
self.root.after(0, lambda: self.update_emulator_status(index, "运行中"))
|
|
|
|
|
|
- try:
|
|
|
- # 启动模拟器
|
|
|
- self.log_message(f"正在启动模拟器 {index}...")
|
|
|
- if not manager.start_emulator(index):
|
|
|
- self.log_message(f"❌ 模拟器 {index} 启动失败")
|
|
|
- results[index] = False
|
|
|
- return
|
|
|
-
|
|
|
- # 等待就绪
|
|
|
- if not manager.wait_for_emulator_ready(index, timeout=180, log_callback=self.log_message):
|
|
|
- self.log_message(f"❌ 模拟器 {index} 启动超时")
|
|
|
- results[index] = False
|
|
|
- return
|
|
|
-
|
|
|
- time.sleep(5)
|
|
|
- if not manager.check_resolution(index, 720, self.log_message):
|
|
|
- self.log_message(f"❌ 模拟器 {index} 分辨率不是720,停止任务并关闭模拟器")
|
|
|
- manager.stop_emulator(index)
|
|
|
- results[index] = False
|
|
|
- self.root.after(0, lambda: self.update_emulator_status(index, "分辨率错误"))
|
|
|
- return
|
|
|
- # 安装APK
|
|
|
- if not manager.install_apk(index, self.apk_path_var.get(), self.log_message):
|
|
|
- self.log_message(f"❌ APK安装失败")
|
|
|
- # results[index] = False
|
|
|
- # return
|
|
|
-
|
|
|
- # 打开应用
|
|
|
- manager.open_app(index, self.package_name_var.get(), self.log_message)
|
|
|
- while manager.get_pixel_color(index, 560, 130, log_callback=self.log_message) != "#EEF8EE" or manager.get_pixel_color(index, 533, 60, log_callback=self.log_message) != "#FFFFFF":
|
|
|
- self.log_message(f"模拟器 {index} 等待进入主界面中...")
|
|
|
- time.sleep(5)
|
|
|
+ manager = MuMuEmulatorManager(self.mumu_path_var.get())
|
|
|
+
|
|
|
+ # 启动模拟器
|
|
|
+ self.log_message(f"正在启动模拟器 {index}...")
|
|
|
+ if not manager.start_emulator(index):
|
|
|
+ self.log_message(f"❌ 模拟器 {index} 启动失败")
|
|
|
+ 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.root.after(0, lambda: self.update_emulator_status(index, "启动超时"))
|
|
|
+ return
|
|
|
+
|
|
|
+ time.sleep(5)
|
|
|
+ if not manager.check_resolution(index, 720, self.log_message):
|
|
|
+ self.log_message(f"❌ 模拟器 {index} 分辨率不是720,停止任务并关闭模拟器")
|
|
|
+ manager.stop_emulator(index)
|
|
|
+ results[index] = False
|
|
|
+ self.root.after(0, lambda: self.update_emulator_status(index, "分辨率错误"))
|
|
|
+ return
|
|
|
+
|
|
|
+ # 安装APK
|
|
|
+ if not manager.install_apk(index, self.apk_path_var.get(), self.log_message):
|
|
|
+ self.log_message(f"⚠️ APK安装失败,但继续执行...")
|
|
|
+
|
|
|
+ # 打开应用
|
|
|
+ manager.open_app(index, self.package_name_var.get(), self.log_message)
|
|
|
+
|
|
|
+ # 等待进入主界面
|
|
|
+ errNumber = 0
|
|
|
+ while True:
|
|
|
+ if self.should_stop or self.is_paused:
|
|
|
+ while self.is_paused and not self.should_stop:
|
|
|
+ time.sleep(1)
|
|
|
+ if self.should_stop:
|
|
|
+ return
|
|
|
|
|
|
- # 执行操作
|
|
|
- self.openBook(manager, index)
|
|
|
+ color560130 = manager.get_pixel_color(index, 560, 130, log_callback=self.log_message)
|
|
|
|
|
|
- # 评价
|
|
|
- time.sleep(8)
|
|
|
- manager.tap(index, 680, 95, self.log_message)
|
|
|
- time.sleep(2)
|
|
|
- manager.tap(index, 633, 930, self.log_message)
|
|
|
+ if color560130 in ["#EEF8EE", "#F7F7F7"]:
|
|
|
+ self.log_message(f"模拟器 {index} 已经进入主界面,继续...")
|
|
|
+ break
|
|
|
+ elif color560130 in ["#5F635F"]:
|
|
|
+ self.log_message(f"模拟器 {index} 需要关闭红包弹窗...")
|
|
|
+ manager.tap(index, 640, 260, self.log_message)
|
|
|
+ time.sleep(20)
|
|
|
+ manager.tap(index, 57, 193, self.log_message)
|
|
|
+ elif color560130 in ["#CED0D2"]:
|
|
|
+ self.log_message(f"模拟器 {index} 需要关闭广告弹窗...")
|
|
|
+ manager.tap(index, 200, 80, self.log_message)
|
|
|
+ elif color560130 in ["#F3CEA9"]:
|
|
|
+ self.log_message(f"模拟器 {index} 进入错误页面,返回...")
|
|
|
+ manager.tap(index, 44, 92, self.log_message)
|
|
|
+ time.sleep(20)
|
|
|
+ manager.tap(index, 57, 193, self.log_message)
|
|
|
+ else:
|
|
|
+ errNumber = errNumber + 1
|
|
|
+ if errNumber > 30:
|
|
|
+ self.log_message(f"模拟器 {index} 连续多次未进入主界面,退出...")
|
|
|
+ manager.stop_emulator(index)
|
|
|
+ results[index] = False
|
|
|
+ self.root.after(0, lambda: self.update_emulator_status(index, "进入主界面失败"))
|
|
|
+ return
|
|
|
|
|
|
- # 发表
|
|
|
+ self.log_message(f"模拟器 {index} 等待进入主界面中...")
|
|
|
time.sleep(5)
|
|
|
- manager.tap(index, 640, 95, self.log_message)
|
|
|
-
|
|
|
- time.sleep(4)
|
|
|
- # 关闭模拟器
|
|
|
- self.log_message(f"正在关闭模拟器 {index}...")
|
|
|
- manager.stop_emulator(index)
|
|
|
-
|
|
|
- self.log_message(f"✅ 模拟器 {index} 任务完成")
|
|
|
- results[index] = True
|
|
|
- self.root.after(0, lambda: self.update_emulator_status(index, "任务完成"))
|
|
|
- except Exception as e:
|
|
|
- self.log_message(f"❌ 模拟器 {index} 执行出错: {e}")
|
|
|
+
|
|
|
+ # 执行打开书籍
|
|
|
+ if not self.openBook(manager, index):
|
|
|
results[index] = False
|
|
|
- self.root.after(0, lambda: self.update_emulator_status(index, "执行出错"))
|
|
|
+ self.root.after(0, lambda: self.update_emulator_status(index, "打开书籍失败"))
|
|
|
+ return
|
|
|
+
|
|
|
+ # 评价
|
|
|
+ time.sleep(8)
|
|
|
+ manager.tap(index, 680, 95, self.log_message)
|
|
|
+ time.sleep(2)
|
|
|
+ manager.tap(index, 633, 930, self.log_message)
|
|
|
+
|
|
|
+ # 发表
|
|
|
+ time.sleep(5)
|
|
|
+ manager.tap(index, 640, 95, self.log_message)
|
|
|
+
|
|
|
+ time.sleep(4)
|
|
|
+
|
|
|
+ # 关闭模拟器
|
|
|
+ self.log_message(f"正在关闭模拟器 {index}...")
|
|
|
+ manager.stop_emulator(index)
|
|
|
+
|
|
|
+ self.log_message(f"✅ 模拟器 {index} 任务完成")
|
|
|
+ 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.root.after(0, lambda: self.update_emulator_status(index, "执行出错"))
|
|
|
+ finally:
|
|
|
+ # 减少活跃线程计数
|
|
|
+ with self.threads_lock:
|
|
|
+ self.active_threads -= 1
|
|
|
+ current_active = self.active_threads
|
|
|
+ self.log_message(f"📊 当前活跃线程数: {current_active}/{max_threads}")
|
|
|
+
|
|
|
+ # 释放信号量
|
|
|
+ self.thread_semaphore.release()
|
|
|
|
|
|
# 启动所有模拟器任务
|
|
|
for emu in self.selected_emulators:
|