From bde168df154e0fd21328eabf23cfa9cb2eb4c353 Mon Sep 17 00:00:00 2001 From: milk <53408947@qq.com> Date: Thu, 30 Oct 2025 20:11:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=9A=E6=97=B6=E9=87=8D?= =?UTF-8?q?=E5=8A=A0=E8=AE=BE=E5=A4=87=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/misc.xml | 2 +- Module/DeviceInfo.py | 39 +++++++ Module/__pycache__/DeviceInfo.cpython-312.pyc | Bin 27289 -> 28984 bytes Module/__pycache__/Main.cpython-312.pyc | Bin 3763 -> 3763 bytes Utils/__pycache__/LogManager.cpython-312.pyc | Bin 14663 -> 14663 bytes script/ScriptManager.py | 107 ++++++++++++------ .../__pycache__/ScriptManager.cpython-312.pyc | Bin 68026 -> 69564 bytes 7 files changed, 113 insertions(+), 35 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 20aef6e..a37b124 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/Module/DeviceInfo.py b/Module/DeviceInfo.py index bbadad2..bdc9906 100644 --- a/Module/DeviceInfo.py +++ b/Module/DeviceInfo.py @@ -116,6 +116,45 @@ class DeviceInfo: self._iproxy_path = self._find_iproxy() LogManager.info("DeviceInfo 初始化完成", udid="system") print("[Init] DeviceInfo 初始化完成") + # 延迟执行删除设备方法 + threading.Thread(target=self.readdDevice).start() + + # 清空所有设备 + def readdDevice(self): + print("开始自动删除设备") + second = 0 + while True: + second += 1 + if second == 3555: + with self._lock: + # 先拍一张快照,避免“边遍历边修改” + udids = list(self._models.keys()) + for udid in udids: + print(f"[Remove] 正在移除设备 {udid}") + # 以 udid 为主键,逐个 pop + model = self._models.pop(udid, None) + proc = self._iproxy.pop(udid, None) + self._port_by_udid.pop(udid, None) + self._first_seen.pop(udid, None) + self._last_seen.pop(udid, None) + # 安全结束进程 + self._kill(proc) + # 组一个“下线通知”的占位模型 + if model is None: + model = DeviceModel( + deviceId=udid, screenPort=-1, width=0, height=0, scale=0.0, type=2 + ) + # 标记为“已移除/离线” + model.type = 2 + model.ready = False + model.screenPort = -1 + # 通知上层 + self._manager_send(model) + print(f"[Remove] 已移除设备 {udid}") + second = 0 + print(f"[Remove] 设备移除完成,总数: {len(udids)}") + time.sleep(1) + def listen(self): LogManager.method_info("进入主循环", "listen", udid="system") diff --git a/Module/__pycache__/DeviceInfo.cpython-312.pyc b/Module/__pycache__/DeviceInfo.cpython-312.pyc index b58179f22e0d15580cf4399c99a8f0c387e9ede7..7d2a3487be85ef73c690568779c0d68f94830997 100644 GIT binary patch delta 3596 zcmZuz3s6+o8NO#9*Ogs%c`e-KwY&0=6@!Xc1tIkTroLhx7!@Du%Du?K!s6MB4}wBx z?5NRNGbd4qCSq#Ts7;C68EGI!JF!V8wgVLlZk>sy;;S`LYny30llK45^3uuO*>C^z zzs`UD$GO{jg>-yH%wI%CMhNhnTcY)Ty!b=&N+XG2RmQHS4B50@S7wqUw+m&FvKi1U zXUZ1EB1b7&Ia(2AqC`~~JdTKY$aob zMj~q)A_ZY90ZLb$B?$WnUC=00X~3R8?3xsjGEE?Ysvly3SRA6^m!;U!*tW#6*_uX8 zv9S6vc+-yBQ{SjPD7>v1*%{5*ob*g{qgED94Q{km$J{d#*wXaam?zkJ&^Dv?6Ko;? zJL-qoF+a?E!o^Pv8HZwGCP)rDvNq17rVX*6 zwR&EPdu1frePoX>O_(AC$R-UDRzN+7uxI*a?FwNNaYa5~FM;JiSM$K}-FJ4J9C+=- zz|OY2tw-;CaBkq}4vIOZ$pCj#0sh6#DqIvx%1YW?F9~3EcJi|Ed~hbeBOXcmvgdO*%An8>-=?e z1 zKpnJ3vvAE2*=^41HMp)v$LtjQ%`yF^n0=mI3wO@zw^& zlO1hw$CHmF_c?QWoVk~sd6$!??JMbbWIPhA);Xj_cTGy^b`*A$cFgNeo!cuFUw5P* zHytsB=eRwtUA^omY|;1I(+)SbHul*k_1Gu1>)PeZ_L(iZekr+6n$ROn=#z4Kq?{9K zdueZzRKVF;JyKSmG_gmTc%rmDuUDD@+{2buOP`e8BW0f`Zcp!(re6nML~BGF$g{2| zIa-RYrBCX2J<~Dn{Or#?-OI|lJ?kE8H5sWbB@YZj=J*!Z1^$uXFt=TN2{R_ zPE6~Srods!yB+x*=^gRisk5#~vma#RDIZJ}QtkWZeLEF0@;Fb3j_;P9?FyWq*4fbE z>yBU88@1?~De4ysb}iVqVb9`+MS>;vTM<+rULpin~RRP$2dxo9{ zkdhp0q-G!*qDM6WHmy?I7ToJ75=n?%%G~SZEj<+!`F<`l?>F9Hlp*&G_UiZ|vX^xg zC$V0jE(K$pG#H}>fE-pP{llE|&#jJ$fi{WVms zMDQZ;`L9B%8o|fzfCjHs)j3a3B{)nK0x?2!c2sA zgbxw+BK#HFC7E1cSBtYqNl;U=N=JUn-1F0(gX41TJSG=*OW)P@SUOGu;o>1ozjYJ+j!Uz$PQVqK+w zBUgfLOYdpONw$0We4`tca}hl3%jFqAVn|*=_#WYZ03l7l8`757$h>?3?0<}qKj9#+ zvVs*UxRks)3aGSS$Lcm}Ps5A@xme@Xvv&Z6WOK&f@RMc&8vL&mk$+lqU zs>4Kl3_5TXtzENz!9yTJ=2CBs;;&arHrIKnB8PPReaz#V3i6@Q_?1(Lw%Ec?g|?AJ zyRGC4Hr{=YY-OFRY{Bfc$z=9w^snQuZc+6Yd&|SkKx@zqcdiY$1zu%gzgnOmui>n2 zW;;D87X#1vkY%0<;+cTOg!c=lA>Q8C>r~z)OmDAzVQC6yXlSMFd_y zyw)gzNGSZh7s4gRQjNMR@p7bV5UdFC2np;=MGWa=7b|Lvk@|v1j&b_LM+-=B`udj% z+0S-YW{lw@LI^usnQJwn@1tnQ@0X8}`igyD`5Ws1lKjr#)6F|Moqgt=NG7qz-u;$! MA}M+#Ao7j>4+YJje*gdg delta 2227 zcmZ9Mdu)?c6u^7CexG%t+hC7wV`UpKMu`j@IM{IV+JKD&raXq*q%FN)S+{nrw=HfZ zb138C0~AjLiONtAC1`|vyrMFU_(lZ(K+T6C28=|M#2`_bF?h}`vO$ymcJ4Xno_oG? z&pk&kuPed|*@VApx57@6W`7rbydQ;9od6@JkKMT*qbp{_JHCZ=zt2`TbXG-1w5mjzS z&#Xk089WCU*}O!$(5WVl?`^Q79L6rZ~syowfy5RtcwCMnT~` ztNuq;I!o>}Ih6&mJgg%0+VfzoeF_@}pV(i4uAFk#0S9wBlFwSpL^e8j8SGax^^Xds ztLi1Hy9tuU1ehDbV`fb;lt@6+!XgLN;$ei59MPg&^Lb){sAwc@HQ_!&1KBNYT4w}) z9#gCumViGJh4hl;%nPBCY}TQ#FR4;lKYToXbCH{NOd_-*oT*|S$%_eb!fJ?=R&X+|vzmV~!>3bP(w;_hB2m+j8KN7iroO}C@axp^@I(G&a8&p(_nwM%tQC?g zJ;jD1G!O5T$%$nYxdvg_TtQE}XQd`w5v`p=Pvu0LVF`0a0GszkyCM;#6CnsK@`$Y*hxpZ#B&Fy zE3{x}m3A{@lRk51t{IEdG`ooHgRa>*EK}b)`-+0q>#1!im08P==%Q%dgeM435@r+D z5_$;hAg?Y@T~Fc$sH`hsPeEf{$&h}Q?932#q;|umx*T=__S6-YK0}IU37ZI;3C|Ip zCu||eR>&Z!6|U8lRDF)3VT}gEu5d_1<@btXWPXA0B4I0G8etpZB|?nw4R+0Nv)B)@ z`D2+w-!Z@0!d`=a7LIzrO=j85`$yM~&n#Flow=~Q&_;cx8tD#0cVx<;^Sq&2(JWF;} zEWv+p%u#4epTJ#80%BMa2cuT!g-cZ1o_D z@zL<%($UPN-)Lwzr}UEX6rl?`8Y9JS5(i4CCL-sOb`8QXM?(T2y(yQSfpJa6OhA3p zMRro3+xe-Zvh80LuINb&}`yxR!93%U~dOZ5F| z_}b-Q-TH5?bTj)B{`C~FufVZlZp}vY#gd<jA;SAvf;*AN)+|!S90i zwae@{EcE8;$9?&1W;42BgWz<+%MMlhy@?AHyC|$YEGbcNIS=GHNoc~lB&u=*@>?A2 zfL__c&Fm`lw#M-3XSEfWubZH}t!(Ob89(faw%j>K9zjdoJ~%<2zn#1MI37DXkHXHj zQ?|#^#mNM9gmWas1C!Y~csJna_Mk#|33RE3Wko0y5Zh@@vs6wfv5zGA{B)Ae6R6n| z7eg~m^b>9nn;-|^bf^#7*dbUR3@Rzgq^o)Qx4}h>b-}n$ z@m)*Et=|MoLuFYCLs输入->发送->返回""" @@ -80,6 +79,8 @@ class ScriptManager(): coord2 = OCRUtils.find_template(str(self.comment_add_dir), filePath) + click_count = False + if coord2: # 二判命中 LogManager.method_info(f"方案1", "养号", udid) cx2, cy2 = coord2[0] @@ -88,6 +89,8 @@ class ScriptManager(): session.send_keys(f"{single_comment}\n") time.sleep(2) LogManager.method_info("评论成功", "养号", udid) + click_count = True + else: time.sleep(1) LogManager.method_info(f"方案2", "养号", udid) @@ -101,13 +104,19 @@ class ScriptManager(): session.send_keys(f"{single_comment}\n") time.sleep(2) LogManager.method_info("评论成功", "养号", udid) + click_count = True # 点返回/取消按钮:优先用推荐按钮坐标,没有就兜底 100,100 tap_x = int(recomend_cx) if recomend_cx else 100 tap_y = int(recomend_cy) if recomend_cy else 100 - session.tap(tap_x, tap_y) - time.sleep(1) - session.tap(tap_x, tap_y) + if click_count: + print("点击一次") + session.tap(tap_x, tap_y) + else: + print("点击两次") + session.tap(tap_x, tap_y) + time.sleep(1) + session.tap(tap_x, tap_y) # 养号 def growAccount(self, udid, isComment, event, is_monitoring=False): @@ -223,6 +232,7 @@ class ScriptManager(): if isComment and random.random() > 0.70: self.comment_flow(filePath, session, udid, recomend_cx, recomend_cy) + event.wait(timeout=2) videoTime = random.randint(15, 30) for _ in range(videoTime): @@ -455,6 +465,8 @@ class ScriptManager(): for i in range(count): LogManager.method_info(f"返回上一步", "关注打招呼", udid) session.appium_settings({"snapshotMaxDepth": 15}) + source = session.source() + LogManager.method_info(f"返回按钮的节点:{source}","返回节点", udid) ControlUtils.clickBack(session) event.wait(timeout=2) @@ -543,7 +555,7 @@ class ScriptManager(): session.appium_settings({"snapshotMaxDepth": 15}) continue - event.wait(timeout=2) + event.wait(timeout=5) # 找到并点击第一个视频 cellClickResult, workCount = ControlUtils.clickFirstVideoFromDetailPage(session) @@ -599,6 +611,7 @@ class ScriptManager(): # 使用OCR进行评论 if isComment: self.comment_flow(filePath, session, udid, 100, 100) + event.wait(timeout=2) if count != 0: ControlUtils.swipe_up(udid) @@ -645,23 +658,32 @@ class ScriptManager(): print("找到输入框了, 准备发送一条打招呼消息") LogManager.method_info("找到输入框了, 准备发送一条打招呼消息", "关注打招呼", udid) - print("打招呼的数据", ev.prologueList) # LogManager.method_info(f"传递的打招呼的数据:{ev.prologueList}", "关注打招呼", udid) # 取出国家进行对应国家语言代码 anchorCountry_code = CountryLanguageMapper.get_language_code(anchorCountry) - print(anchorCountry_code) - print("存储的是:",ev.prologueList) + + LogManager.method_info(f"获取的语言代码是:{ev.prologueList}","关注打招呼",udid) + + LogManager.method_info(f"存储的打招呼语句是:{ev.prologueList}","关注打招呼",udid) + # 判断对应的语言代码是否在传入的字典中 if anchorCountry_code in ev.prologueList: + + LogManager.method_info(f"在存储的字典中 打招呼语句是:{ev.prologueList}", "关注打招呼", udid) + # 进行原本的进行传入 privateMessageList = ev.prologueList[anchorCountry_code] + + needTranslate = False else: + + LogManager.method_info(f"不在存储的字典中 打招呼语句是:{ev.prologueList}", "关注打招呼", udid) # 需要翻译 privateMessageList = ev.prologueList['yolo'] needTranslate = True # 使用yolo必须翻译 @@ -1315,6 +1337,7 @@ class ScriptManager(): sel = session.xpath("//TextView") if anchor_name not in anchorWithSession: + print("没有记忆") # 如果是第一次发消息(没有sessionId的情况) LogManager.method_info(f"第一次发消息:{anchor_name},没有记忆 开始请求ai", "检测消息", udid) @@ -1328,15 +1351,14 @@ class ScriptManager(): if last_out: text = last_out - - if sel.exists: sel.click() # 聚焦 event.wait(timeout=1) sel.clear_text() - LogManager.method_info(f"发送的消息,检测不到对方发送的消息,不走ai:{text or '暂无数据'}", "检测消息", - udid) + LogManager.method_info( + f"发送的消息,检测不到对方发送的消息,不走ai:{text or '暂无数据'}", "检测消息", + udid) sel.set_text(f"{text or '暂无数据'}\n") else: @@ -1352,42 +1374,59 @@ class ScriptManager(): sel.click() # 聚焦 event.wait(timeout=1) sel.clear_text() - LogManager.method_info(f"发送的消息,检测到对方发送的消息,进行走ai(没记忆):{aiResult or '暂无数据'}", "检测消息", - udid) + LogManager.method_info( + f"发送的消息,检测到对方发送的消息,进行走ai(没记忆):{aiResult or '暂无数据'}", + "检测消息", + udid) sel.set_text(f"{aiResult or '暂无数据'}\n") else: LogManager.method_error("找不到输入框,重启", "检测消息", udid) raise Exception("找不到输入框,重启") else: + print("有记忆") + LogManager.method_info(f"不是一次发消息:{anchor_name},有记忆", "检测消息", udid) # 如果不是第一次发消息(证明存储的有sessionId) sessionId = anchorWithSession[anchor_name] - # TODO: user后续添加,暂时写死 + if last_in is None: + last_in = "ok" + if sel.exists: + sel.click() # 聚焦 + event.wait(timeout=1) + sel.clear_text() + LogManager.method_info( + f"发送的消息,检测到对方发送的消息,进行走ai(有记忆):{last_in or '暂无数据'}", + "检测消息", + udid) + sel.set_text(f"{last_in or '暂无数据'}\n") + else: - LogManager.method_info(f"向ai发送的参数: 文本为:{last_in}", "检测消息", udid) + # TODO: user后续添加,暂时写死 - aiResult, sessionId = Requester.chatToAi( - {"query": last_in, "conversation_id": sessionId, "user": "1"}) + LogManager.method_info(f"向ai发送的参数: 文本为:{last_in}", "检测消息", udid) - if sel.exists: - sel.click() # 聚焦 - event.wait(timeout=1) - sel.clear_text() - LogManager.method_info( - f"发送的消息,检测到对方发送的消息,进行走ai(有记忆):{aiResult or '暂无数据'}", - "检测消息", - udid) - sel.set_text(f"{aiResult or '暂无数据'}\n") + aiResult, sessionId = Requester.chatToAi( + {"query": last_in, "conversation_id": sessionId, "user": "1"}) - LogManager.method_info(f"存储的sessionId:{anchorWithSession}", "检测消息", udid) - event.wait(timeout=1) - # 返回 - ControlUtils.clickBack(session) + if sel.exists: + sel.click() # 聚焦 + event.wait(timeout=1) + sel.clear_text() + LogManager.method_info( + f"发送的消息,检测到对方发送的消息,进行走ai(有记忆):{aiResult or '暂无数据'}", + "检测消息", + udid) + sel.set_text(f"{aiResult or '暂无数据'}\n") - # 重新回到收件箱页面后,强制刷新节点 - session.appium_settings({"snapshotMaxDepth": 25}) - event.wait(timeout=1) + LogManager.method_info(f"存储的sessionId:{anchorWithSession}", "检测消息", udid) + event.wait(timeout=1) + # 返回 + ControlUtils.clickBack(session) + + # 重新回到收件箱页面后,强制刷新节点 + session.appium_settings({"snapshotMaxDepth": 25}) + event.wait(timeout=1) try: # 如果 2 秒内找不到,会抛异常 diff --git a/script/__pycache__/ScriptManager.cpython-312.pyc b/script/__pycache__/ScriptManager.cpython-312.pyc index c3277f60c3e15804cd7879965daa045e1d55d891..5fe13b32793ed0a2542e8cde50081c398ae43da8 100644 GIT binary patch delta 7003 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 DxpNY? delta 6102 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