J-8RUrye9b7s4M4hN(d{QF04*yN9lXvW%
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
R1TMuqJpN-F*xBKT@DHVMa@PO=
diff --git a/Module/__pycache__/Main.cpython-312.pyc b/Module/__pycache__/Main.cpython-312.pyc
index 9e23e1d7d70d829bf3c644c830f85ab2c637285d..993b37132f6af8c518b6e69ae2baeaacf281d2d9 100644
GIT binary patch
delta 20
acmbOwJ4=@PG%qg~0}wR&{olyl&j$cE*9DLO
delta 20
acmbOwJ4=@PG%qg~0}!-K`L~g~pAP^ziv`#K
diff --git a/Utils/ThreadManager.py b/Utils/ThreadManager.py
index 6d2a802..632cabe 100644
--- a/Utils/ThreadManager.py
+++ b/Utils/ThreadManager.py
@@ -94,12 +94,20 @@ class ThreadManager:
except Exception as e:
LogManager.method_error(f"[{udid}] 设置停止事件失败: {e}", "task")
- # 🔹 不阻塞主线程
def _wait_stop():
+ # 先给 1 秒高频检查机会(很多 I/O 点会在这个窗口立刻感知到)
+ t0 = time.time()
+ while time.time() - t0 < 1.0 and thread.is_alive():
+ time.sleep(0.05)
+
+ # 再进入原有的 join 窗口
thread.join(timeout=stop_timeout)
if thread.is_alive():
LogManager.method_info(f"[{udid}] 协作超时 -> 尝试强杀", "task")
- _async_raise(tid)
+ try:
+ _async_raise(tid) # 兜底:依然保留你的策略
+ except Exception as e:
+ LogManager.method_error(f"[{udid}] 强杀触发失败: {e}", "task")
thread.join(timeout=kill_timeout)
if not thread.is_alive():
@@ -136,10 +144,15 @@ class ThreadManager:
with ThreadPoolExecutor(max_workers=4) as executor:
futures = {executor.submit(cls.stop, udid): udid for udid in ids}
for future in as_completed(futures):
- code, msg = future.result()
+ udid = futures[future]
+ try:
+ code, msg = future.result()
+ except Exception as e:
+ LogManager.method_error(f"[{udid}] stop 调用异常: {e}", "task")
+ failed.append(udid)
+ continue
if code != 200:
- failed.append(futures[future])
-
+ failed.append(udid)
if failed:
return 207, f"部分任务停止失败: {failed}"
return 200, "全部停止请求已提交"
\ No newline at end of file
diff --git a/Utils/__pycache__/LogManager.cpython-312.pyc b/Utils/__pycache__/LogManager.cpython-312.pyc
index 7d1bd6e1d99c3365ff1897afbd8ac4c2004237f2..5063933152f9f0b88302bb17a462bca5b166d6c1 100644
GIT binary patch
delta 20
acmX?Jbi9cBG%qg~0}yok{olxKV+jCCLF7(Vyj-rL@m0=>PLLQCuAOQ=-@6jay-h%lYV+;kvQ!z#rOzIR*2Ev=X>
zW;S8da@=5XCYa5MbIC9)i&^}kI2V%rDGNr^@WW+ey8S92i3XFo_uRrjXW}J1=eh5B
z&vV{;&UsExRO0IRUyMdQf~S1flY=RiEAhQ?)cxV}acwM>hZBT!Di;?Bxxn4RCaV_m
z%q9<@421`eB}n)luQLSx9~1oOeVD>Swa^GD+kns1p!f%ycDvfjtz>t_3EO;CFldDwG|hr0}AkcUD%
z@)=_sp&++(bWDYkQtw?gle6nkE*mw&o9NH+@$6E3!eP)ZR0rk9eM
zEsN0w7S!VPqAd907Xq0`SstKb(>P<(X#Lb#bWXGM+v<@A1*l_G&v2~8Vq8X|zUDwo
zC0eSi0*2oeH&~N^?3E|4{rKm(;}0%=J$WiL`PG#N-(M(}@g;HVTX9MeBq-?w)&WE`
z%^io@6&-mO30Mh81W1WWJ^?#{3;?GtLi_TRWb&R#;3WbjIA1bzL_(JFW~p?a8>qJi
z_W#jw^oL36O9`c5+sTa+LQ(Q(kC8tdz
zN=u7hEC&RS{Z_|F%|B1$dn;i}DZewK*s~4{>lani;_-Qa_Oj5DIX9*3YFtETG|$
zpKIp9uHAdUH34lv=hu3;7B~l9swdq~H=7{sna8hLbW+b+4YPb*rF)}!;&
zaBAuO^bYhM-$+xakq&6OPzLg;HxiMBv%W6CgG+IcPVHv=8ZfcOQ->T`KsZLR35O
z$M~L;U4NF&!G{#;*&T~J^)-KKpadrsF|@glHgt91u${|t
zLFh0!?R#afucK3bF!bU5GlP@YKA60EwOCf-pa(Ycj(r8(nY1Ibj919&MmX=`eQk$)
z$`;a3WFwr?#smTjrUYU2LZ4)^>{z;QsPZY
z`TrIjYK1^qh*GCr@5
zBA|nXL*}8zq2x=Y)8tjno}z&%*<`*{0H;YwAe_{%6yXbLjgp7ZMgr=!O0tyw*q)wD
Twcw)kvV>z4RWOYRsxtoql3CX>
delta 1264
zcmZvbUuauZ9LLYOH}|GVlcxF8B+b7iO}Z{y*EY%0(oNT`>l8*iaqWWzAIx&ItzFX8
zdsC{A!W4!^%9`yc>!@R$_z<1b)`A=2gLZopAH)eE>_K5Iz6j|mR5}EIzng+=?!x_?
z-#NeU`Q7h5f7sx~;|)I=jd}u4;P#Vq)3)V?D+YRY<)$Gc&`xHuw9x%5YUzMDVHxNZ
zL1%?`^E*n&N8(jd;Kw0)_9<{*&|5p>6gB)6vr8lQWpiAUecb&2
zY(Ze%O@8J#I5_P|_Ipz=i`!3(=qj4=?AV0d0u$sqgbm?BG$6VVUPKTO7UdAehY$x5
zeuNI;11Px2>`!~2=`{B40{*^0$_5L&|Hj`YYDp~ih1h;0S`
zXSLmX%);NZ2*=#okuX;ga|!uuDpwJuL@JY=2y=2LsHU0#Ywvu#e*2R@zPhu%{O;PF
zuh-{_kG}mhY?Qm$Bj>=rC@8}EnpLz_v#OeI#qJ)26LFLcH*eOr8+G6V@RyIh>hjU>
z%B1T(PCSf?{p=slL2&@XBkV=*AdRpOysb31vgGwqJuVp!?`AhE`z~q0-;9_S*`nKH
ze;xL6MmtlN*Gl~P9#{=J>&bJh*l4rmg}m4dv;I3dvk~^wuI89V67t*vxz3&8hRNGv
zlA|Qa&1j}ckVK%sH1tPdmnoTbzQvD{X&TnD8-6>S@QQygPzZz~qKt+rqB3
zgKvb6gRml;8q6lotEaM3pG+qdC6mgX%S!TY$jUFVFN1DRuPQu~&L(#LK7u(d;x)Dw
z{KnoUw9oTZ0!=BdHs7b9Vap+_3C1>gBATllMAcL5mr$UuUWm?*EC#QQRtbcq_>y%g
zx#aw;?=f~&^#%u#+=gH90K#V3gfTjn<1E&i?7-_FClKn@LX|8b)Jb?2w(DNVWTmNe
V>aaYy-8{GF+r-Le*w*IAMXGF
diff --git a/script/ScriptManager.py b/script/ScriptManager.py
index 9148755..78de124 100644
--- a/script/ScriptManager.py
+++ b/script/ScriptManager.py
@@ -49,6 +49,29 @@ class ScriptManager():
self.initialized = True # 标记已初始化
+ # 放在类里或公共工具模块里均可
+ def interruptible_wait(self,event: threading.Event, total: float, step: float = 0.2) -> bool:
+ """
+ 等待 total 秒,但每 step 秒检查一次停止信号。
+ 若在等待期间 event 被置位,立刻返回 True;否则到点返回 False。
+ """
+ deadline = time.time() + total
+ while time.time() < deadline:
+ if event.is_set():
+ return True
+ event.wait(timeout=min(step, max(0, deadline - time.time())))
+ return event.is_set()
+
+ def interruptible_sleep(self,event: threading.Event, seconds: float, step: float = 0.2) -> bool:
+ """语义同上;返回 True 表示期间接到停止信号。"""
+ return self.interruptible_wait(event, seconds, step)
+
+ def check_stop(self,event: threading.Event, tag: str = ""):
+ """在关键点快速失败,保持调用栈整洁(不改变业务路径,只是早退出)。"""
+ if event.is_set():
+ raise RuntimeError(f"stop-requested:{tag}")
+
+
# ========= 评论逻辑 =========
def comment_flow(self, filePath, session, udid, recomend_cx, recomend_cy):
"""评论一条龙:点评论框->输入->发送->返回"""
@@ -57,9 +80,7 @@ class ScriptManager():
if not coord:
return # 没检测到评论按钮就拉倒
- print(11111111111)
cx, cy = coord[0] # ✅ 注意这里取第一个点
-
session.click(int(cx / 3), int(cy / 3))
print(f"点击评论的坐标:{int(cx / 3)}, {int(cy / 3)}")
@@ -412,7 +433,6 @@ class ScriptManager():
"""
def safe_greetNewFollowers(self, udid, needReply, needTranslate, isComment, event):
-
retries = 0
while not event.is_set():
try:
@@ -428,9 +448,11 @@ class ScriptManager():
break
LogManager.method_error("greetNewFollowers 重试次数耗尽,任务终止", "关注打招呼", udid)
- # 关注打招呼以及回复主播消息
def greetNewFollowers(self, udid, needReply, needTranslate, isComment, event):
+ if self.check_stop(event, "init"): # [ADD]
+ return
+
client = wda.USBClient(udid, ev.wdaFunctionPort)
session = client.session()
@@ -441,12 +463,18 @@ class ScriptManager():
# 先关闭Tik Tok
ControlUtils.closeTikTok(session, udid)
- event.wait(timeout=1)
+ if self.interruptible_sleep(event, 1): # [ADD] 可中断等待
+ return
+
+ if self.check_stop(event, "after-close-app"): # [ADD]
+ return
# 重新打开Tik Tok
ControlUtils.openTikTok(session, udid)
- event.wait(timeout=3)
+ if self.interruptible_sleep(event, 3): # [ADD]
+ return
LogManager.method_info(f"重启tiktok", "关注打招呼", udid)
+
# 设置查找深度
session.appium_settings({"snapshotMaxDepth": 15})
@@ -457,10 +485,12 @@ class ScriptManager():
def goBack(count):
for i in range(count):
LogManager.method_info(f"返回上一步", "关注打招呼", udid)
-
+ if self.check_stop(event, f"goBack-{i + 1}/{count}"): # [ADD]
+ return
session.appium_settings({"snapshotMaxDepth": 15})
ControlUtils.clickBack(session)
- event.wait(timeout=2)
+ if self.interruptible_sleep(event, 2): # [ADD]
+ return
LogManager.method_info(f"循环条件1:{not event.is_set()}", "关注打招呼", udid)
LogManager.method_info(f"循环条件2:{len(anchorList) > 0}", "关注打招呼", udid)
@@ -469,13 +499,15 @@ class ScriptManager():
# 循环条件。1、 循环关闭 2、 数据处理完毕
while not event.is_set():
+ if self.check_stop(event, "loop-top"): # [ADD]
+ return
+
LogManager.method_info("=== 外层 while 新一轮 ===", "关注打招呼", udid)
if event.is_set():
break
# 获取一个主播,
LogManager.method_info(f"开始获取数据", "关注打招呼", udid)
- # 获取一个主播,
result = AiUtils.peek_aclist_first()
LogManager.method_info(f"数据是:{result}", "关注打招呼", udid)
@@ -493,17 +525,21 @@ class ScriptManager():
if not anchor:
LogManager.method_info(f"数据库中的数据不足", "关注打招呼", udid)
+ # 你原来的写法:等待完成就 continue;中途被打断就 return
if not self.interruptible_sleep(event, 30):
continue
+ return # [ADD] 被打断则退出
aid = anchor.get("anchorId", "")
anchorCountry = anchor.get("country", "")
LogManager.method_info(f"主播的数据,用户名:{aid},国家:{anchorCountry}", "关注打招呼", udid)
+ if self.check_stop(event, "before-search"): # [ADD]
+ return
+
# 点击搜索按钮
ControlUtils.clickSearch(session)
-
LogManager.method_info(f"点击搜索按钮", "关注打招呼", udid)
# 强制刷新session
@@ -515,20 +551,21 @@ class ScriptManager():
# 如果找到了输入框,就点击并且输入内容
if input.exists:
input.click()
- # 稍作停顿
- event.wait(timeout=0.5)
+ # 稍作停顿(用你的可中断等待)
+ if self.interruptible_sleep(event, 0.5): # [ADD]
+ return
else:
print(f"找不到输入框")
input = session.xpath('//XCUIElementTypeSearchField')
if input.exists:
input.clear_text()
- event.wait(timeout=1)
+ if self.interruptible_sleep(event, 1): # [ADD]
+ return
# 输入主播id
input.set_text(f"{aid or '暂无数据'}\n")
# 定位 "关注" 按钮 通过关注按钮的位置点击主播首页
-
session.appium_settings({"snapshotMaxDepth": 25})
try:
@@ -543,15 +580,22 @@ class ScriptManager():
session.appium_settings({"snapshotMaxDepth": 15})
continue
- event.wait(timeout=2)
+ if self.interruptible_sleep(event, 2): # [ADD]
+ return
+
# 找到并点击第一个视频
cellClickResult, workCount = ControlUtils.clickFirstVideoFromDetailPage(session)
-
LogManager.method_info(f"点击第一个视频", "关注打招呼", udid)
- event.wait(timeout=2)
+
+ if self.interruptible_sleep(event, 2): # [ADD]
+ return
# 观看主播视频
def viewAnchorVideo(workCount):
+
+ if self.check_stop(event, "viewVideo-enter"): # [ADD]
+ return
+
print("开始查看视频,并且重新调整查询深度")
session.appium_settings({"snapshotMaxDepth": 5})
@@ -566,12 +610,16 @@ class ScriptManager():
LogManager.method_info("停止脚本中", method="task")
if event.is_set():
break
- event.wait(timeout=1)
+ if self.interruptible_sleep(event, 1): # [ADD]
+ return
LogManager.method_info("停止脚本成功", method="task")
- img = client.screenshot()
- event.wait(timeout=1)
- # filePath = f"resources/{udid}/bgv.png"
+ if self.check_stop(event, "before-screenshot"): # [ADD]
+ return
+
+ img = client.screenshot()
+ if self.interruptible_sleep(event, 1): # [ADD]
+ return
base_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) # 当前脚本目录的上一级
filePath = os.path.join(base_dir, "resources", udid, "bgv.png")
@@ -582,13 +630,12 @@ class ScriptManager():
img.save(filePath)
LogManager.method_info("保存屏幕图像成功", "关注打招呼", udid)
- event.wait(timeout=2)
+ if self.interruptible_sleep(event, 2): # [ADD]
+ return
+
# 查找add图标
r = ControlUtils.clickLike(session, udid)
- # 点赞成功。
- # if r == True:
-
count -= 1
LogManager.method_info("准备停止脚本", method="task")
# 随机看视频 15~30秒
@@ -596,7 +643,8 @@ class ScriptManager():
LogManager.method_info("停止脚本中", method="task")
if event.is_set():
break
- event.wait(timeout=1)
+ if self.interruptible_sleep(event, 1): # [ADD]
+ return
LogManager.method_info("停止脚本成功", method="task")
# 使用OCR进行评论
@@ -617,16 +665,20 @@ class ScriptManager():
# 观看主播视频
LogManager.method_info("去查看主播视频", "关注打招呼", udid)
viewAnchorVideo(workCount)
- event.wait(timeout=3)
+ if self.interruptible_sleep(event, 3): # [ADD]
+ return
LogManager.method_info("视频看完了,重置试图查询深度", "关注打招呼", udid)
session.appium_settings({"snapshotMaxDepth": 25})
- event.wait(timeout=0.5)
+ if self.interruptible_sleep(event, 0.5): # [ADD]
+ return
# 向上滑动
ControlUtils.swipe_down(udid)
- event.wait(timeout=2)
+ if self.interruptible_sleep(event, 2): # [ADD]
+ return
msgButton = AiUtils.getSendMesageButton(session)
- event.wait(timeout=2)
+ if self.interruptible_sleep(event, 2): # [ADD]
+ return
if msgButton.exists:
# 进入聊天页面
@@ -640,7 +692,8 @@ class ScriptManager():
session.appium_settings({"snapshotMaxDepth": 15})
continue
- event.wait(timeout=3)
+ if self.interruptible_sleep(event, 3): # [ADD]
+ return
# 查找聊天界面中的输入框节点
chatInput = session.xpath("//TextView")
if chatInput.exists:
@@ -653,14 +706,11 @@ class ScriptManager():
# 准备打招呼的文案
text = random.choice(ev.prologueList)
- # text = "hello"
LogManager.method_info(f"取出打招呼的数据,{text}, 判断是否需要翻译:{needTranslate}", "关注打招呼",
udid)
- # isContainChniese = AiUtils.contains_chinese(text)
if needTranslate:
- # 翻译成主播国家的语言
LogManager.method_info(f"需要翻译:{text},参数为:国家为{anchorCountry}, 即将进行翻译",
"关注打招呼", udid)
msg = Requester.translation(text, anchorCountry)
@@ -674,10 +724,10 @@ class ScriptManager():
if chatInput.exists:
chatInput.click()
chatInput.set_text(f"{msg or '暂无数据'}\n")
- event.wait(timeout=2)
- # 发送消息
- # input.set_text(f"{aid or '暂无数据'}\n")
- event.wait(timeout=1)
+ if self.interruptible_sleep(event, 2): # [ADD]
+ return
+ if self.interruptible_sleep(event, 1): # [ADD]
+ return
else:
print("无法发送信息")
LogManager.method_info(f"给主播{aid} 发送消息失败", "关注打招呼", udid)
@@ -685,27 +735,6 @@ class ScriptManager():
# 接着下一个主播
goBack(1)
- # 点击关注按钮
- # followButton = AiUtils.getFollowButton(session).get(timeout=5)
- # if followButton is not None:
- # # LogManager.method_info("找到关注按钮了", "关注打招呼", udid)
- # # followButton.click()
- # x, y, w, h = followButton.bounds
- # cx = int(x + w / 2)
- # cy = int(y + h / 2)
- # # 随机偏移 ±5 px(可自己改范围)
- # cx += random.randint(-5, 5)
- # cy += random.randint(-5, 5)
- #
- # session.click(cx, cy)
- #
- # else:
- # LogManager.method_info("没找到关注按钮", "关注打招呼", udid)
- # time.sleep(1)
- # goBack(4)
- # session.appium_settings({"snapshotMaxDepth": 15})
- # continue
-
session.appium_settings({"snapshotMaxDepth": 15})
goBack(3)
@@ -718,7 +747,8 @@ class ScriptManager():
# 设置查找深度
session.appium_settings({"snapshotMaxDepth": 15})
- event.wait(timeout=2)
+ if self.interruptible_sleep(event, 2): # [ADD]
+ return
print("即将要回复消息")
LogManager.method_info("即将要回复消息", "关注打招呼", udid)
@@ -735,9 +765,11 @@ class ScriptManager():
homeButton.click()
else:
ControlUtils.closeTikTok(session, udid)
- event.wait(timeout=2)
+ if self.interruptible_sleep(event, 2): # [ADD]
+ return
ControlUtils.openTikTok(session, udid)
- event.wait(timeout=3)
+ if self.interruptible_sleep(event, 3): # [ADD]
+ return
print("重新创建wda会话 防止wda会话失效")
client = wda.USBClient(udid, ev.wdaFunctionPort)
diff --git a/script/__pycache__/ScriptManager.cpython-312.pyc b/script/__pycache__/ScriptManager.cpython-312.pyc
index 78f3251be854ab035111a113ae1d039b57c1c9d0..8a385046201e05b3a53ae70ad0f5cc92cb0c9b60 100644
GIT binary patch
delta 12987
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