diff --git a/.gitignore b/.gitignore index 64bff02..63cbf57 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,8 @@ var/ .installed.cfg *.egg out/ +Main.build/ +Main.dist/ # PyInstaller # Usually these files are written by a python script from a template @@ -128,4 +130,5 @@ dmypy.json # Cython debug symbols cython_debug/ -*.bat \ No newline at end of file +build-tidevice.bat +build.bat \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 8c600d7..cfda8d8 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -5,37 +5,12 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + diff --git a/Module/FlaskService.py b/Module/FlaskService.py index 9d38520..f9119e2 100644 --- a/Module/FlaskService.py +++ b/Module/FlaskService.py @@ -393,9 +393,12 @@ def upLoadLogLogs(): # 获取当前的主播列表数据 @app.route("/anchorList", methods=['POST']) def queryAnchorList(): - file_path = "log/acList.json" + # 项目根目录(当前文件在 infos 下,回退两层到根目录) + root_dir = Path(__file__).resolve().parent.parent + file_path = root_dir / "log" / "acList.json" + data = [] - if Path(file_path).exists(): + if file_path.exists(): try: with open(file_path, "r", encoding="utf-8") as f: data = json.load(f) @@ -421,14 +424,14 @@ def updateAnchorList(): new_status = 1 if state else 0 # 用工具类解析路径,避免 cwd 影响 - file_path = AiUtils._resolve_path("Module/log/acList.json") + file_path = AiUtils._resolve_path("log/acList.json") # 加载 JSON try: doc = json.loads(file_path.read_text(encoding="utf-8-sig")) except Exception as e: LogManager.error(f"[updateAnchorList] 读取失败: {e}") - return ResultData(code=500, massage=f"读取失败: {e}").toJson() + return ResultData(code=1001, message=f"暂无数据").toJson() # 定位 anchorList if isinstance(doc, list): @@ -438,7 +441,7 @@ def updateAnchorList(): acList = doc["anchorList"] wrapper = doc else: - return ResultData(code=500, massage="文件格式不合法").toJson() + return ResultData(code=500, message="文件格式不合法").toJson() # 遍历并更新 updated = 0 @@ -454,19 +457,12 @@ def updateAnchorList(): file_path.write_text(json.dumps(to_write, ensure_ascii=False, indent=2), encoding="utf-8") except Exception as e: LogManager.error(f"[updateAnchorList] 写入失败: {e}") - return ResultData(code=500, massage=f"写入失败: {e}").toJson() + return ResultData(code=500, message=f"写入失败: {e}").toJson() if updated: - return ResultData(data=updated, massage=f"已更新 {updated} 条记录").toJson() + return ResultData(data=updated, message=f"已更新 {updated} 条记录").toJson() else: - return ResultData(data=0, massage="未找到符合条件的记录").toJson() - - - - - - - + return ResultData(data=0, message="未找到符合条件的记录").toJson() # 删除主播 @@ -538,6 +534,12 @@ def delete_last_message(): return ResultData(data=updated_count, message="修改成功").toJson() return ResultData(data=updated_count, message="修改失败").toJson() +#的停止所有任务 +@app.route("/stopAllTask", methods=['POST']) +def stopAllTask(): + idList = request.get_json() + code, data , msg = ThreadManager.batch_stop(idList) + return ResultData(code, data, msg).toJson() # @app.route("/killWda", methods=['POST']) # def killWda(): diff --git a/Module/__pycache__/FlaskService.cpython-312.pyc b/Module/__pycache__/FlaskService.cpython-312.pyc index fd3e282..c2add39 100644 Binary files a/Module/__pycache__/FlaskService.cpython-312.pyc and b/Module/__pycache__/FlaskService.cpython-312.pyc differ diff --git a/Utils/AiUtils.py b/Utils/AiUtils.py index 28c726a..cdbe7a3 100644 --- a/Utils/AiUtils.py +++ b/Utils/AiUtils.py @@ -686,15 +686,16 @@ class AiUtils(object): def save_aclist_flat_append(cls, acList, filename="log/acList.json"): """ 将 anchor 对象数组平铺追加到 JSON 文件(数组)中。 - 期望 acList 形如: - [ - {"anchorId": "ldn327_", "country": ""}, - {"anchorId": "tianliang30", "country": ""} - ] + 文件固定写到 项目根目录/log/acList.json """ + # 找到当前文件所在目录,回退到项目根目录 + root_dir = Path(__file__).resolve().parent.parent # 根据实际层级调整 + log_dir = root_dir + log_dir.mkdir(parents=True, exist_ok=True) # 确保 log 目录存在 + + file_path = log_dir / filename - file_path = Path(filename) data = cls._read_json_list(file_path) # 规范化输入,确保都是 {anchorId, country} @@ -705,30 +706,12 @@ class AiUtils(object): data.extend(to_add) cls._write_json_list(file_path, data) + LogManager.method_info(f"写入的路径是:{file_path}", "写入数据") LogManager.info(f"[acList] 已追加 {len(to_add)} 条,当前总数={len(data)} -> {file_path}") - # -------- 弹出(取一个删一个) -------- - # @classmethod - # def pop_aclist_first(cls, filename="log/acList.json"): - # """ - # 从 JSON 数组中取出第一个 anchor 对象,并删除它;为空或文件不存在返回 None。 - # 返回形如:{"anchorId": "...", "country": "..."} - # """ - # file_path = Path(filename) - # data = cls._read_json_list(file_path) - # if not data: - # return None - # - # first = data.pop(0) - # # 兜底保证结构 - # norm = cls._normalize_anchor_items(first) - # first = norm[0] if norm else None - # - # cls._write_json_list(file_path, data) - # return first @classmethod - def pop_aclist_first(cls, filename="Module/log/acList.json", mode="pop"): + def pop_aclist_first(cls, filename="log/acList.json", mode="pop"): """ 从 JSON 数组/对象(anchorList)中取出第一个 anchor 对象。 - mode="pop" : 取出并删除 @@ -867,12 +850,16 @@ class AiUtils(object): @classmethod def delete_anchors_by_ids(cls, ids: list[str], filename="log/acList.json") -> int: """ - 根据 anchorId 列表从 JSON 文件中删除匹配的 anchor。 + 根据 anchorId 列表从根目录/log/acList.json 中删除匹配的 anchor。 返回删除数量。 """ - file_path = Path(filename) + # 确保路径固定在根目录下的 log 文件夹 + root_dir = Path(__file__).resolve().parent.parent + file_path = root_dir / "log" / filename + if not file_path.exists(): return 0 + try: with open(file_path, "r", encoding="utf-8") as f: data = json.load(f) @@ -881,15 +868,19 @@ class AiUtils(object): except Exception as e: LogManager.error(f"[delete_anchors_by_ids] 读取失败: {e}") return 0 + before = len(data) # 保留不在 ids 里的对象 data = [d for d in data if isinstance(d, dict) and d.get("anchorId") not in ids] deleted = before - len(data) + try: + file_path.parent.mkdir(parents=True, exist_ok=True) with open(file_path, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) except Exception as e: LogManager.error(f"[delete_anchors_by_ids] 写入失败: {e}") + return deleted # -------- 查看第一个(取出但不删除) -------- @@ -903,7 +894,7 @@ class AiUtils(object): return (base / p).resolve() @classmethod - def peek_aclist_first(cls, filename="Module/log/acList.json"): + def peek_aclist_first(cls, filename="log/acList.json"): file_path = cls._resolve_path(filename) if not file_path.exists(): print(f"[peek] 文件不存在: {file_path}") diff --git a/Utils/ThreadManager.py b/Utils/ThreadManager.py index 6740d08..649ce29 100644 --- a/Utils/ThreadManager.py +++ b/Utils/ThreadManager.py @@ -1,5 +1,6 @@ import threading -from typing import Dict, Tuple +from concurrent.futures import ThreadPoolExecutor, as_completed +from typing import Dict, Tuple, List from Utils.LogManager import LogManager @@ -64,6 +65,37 @@ class ThreadManager: LogManager.method_info(f"设备 {udid} 的任务停止成功", method="task") return 200, f"当前任务停止成功 {udid}" + @classmethod + def batch_stop(cls, udids: List[str]) -> Tuple[int, List[str], str]: + """ + 批量停止任务,使用多线程并发执行。 + :param udids: 待停止的设备唯一标识列表 + :return: (code, fail_list, msg) + code=200 全部成功,fail_list=[] + code=1001 部分/全部失败,fail_list 为失败描述字符串列表 + """ + if not udids: + return 200, [], "无设备需要停止" + + fail_list: List[str] = [] + + with ThreadPoolExecutor(max_workers=min(32, len(udids))) as executor: + future_map = {executor.submit(cls.stop, udid): udid for udid in udids} + + for future in as_completed(future_map): + udid = future_map[future] + try: + code, reason = future.result() + if code != 200: + fail_list.append(f"设备{udid}停止失败:{reason}") + except Exception as exc: + fail_list.append(f"设备{udid}停止异常:{exc}") + + if fail_list: + return 1001, fail_list, "停止失败" + return 200, [], "全部设备停止成功" + + @classmethod def is_task_running(cls, udid: str) -> bool: """ diff --git a/Utils/__pycache__/AiUtils.cpython-312.pyc b/Utils/__pycache__/AiUtils.cpython-312.pyc index a8e6334..bd1d433 100644 Binary files a/Utils/__pycache__/AiUtils.cpython-312.pyc and b/Utils/__pycache__/AiUtils.cpython-312.pyc differ diff --git a/Utils/__pycache__/LogManager.cpython-312.pyc b/Utils/__pycache__/LogManager.cpython-312.pyc index 4b060c9..7f942a0 100644 Binary files a/Utils/__pycache__/LogManager.cpython-312.pyc and b/Utils/__pycache__/LogManager.cpython-312.pyc differ diff --git a/Utils/__pycache__/ThreadManager.cpython-312.pyc b/Utils/__pycache__/ThreadManager.cpython-312.pyc index 77f7231..73e2d2b 100644 Binary files a/Utils/__pycache__/ThreadManager.cpython-312.pyc and b/Utils/__pycache__/ThreadManager.cpython-312.pyc differ diff --git a/script/ScriptManager.py b/script/ScriptManager.py index 26b177d..a14de8f 100644 --- a/script/ScriptManager.py +++ b/script/ScriptManager.py @@ -244,7 +244,7 @@ class ScriptManager(): session.double_tap(x, y) print("--------------------------------------------") - time.sleep(random.randint(180, 300)) + time.sleep(random.randint(300, 600)) session.swipe_up() # 正常退出(外部 event 触发) @@ -320,11 +320,16 @@ class ScriptManager(): # 循环条件。1、 循环关闭 2、 数据处理完毕 while not event.is_set(): + # 获取一个主播, + LogManager.method_info(f"开始获取数据", "关注打招呼", udid) # 获取一个主播, result = AiUtils.peek_aclist_first() - state = result.get("state",0) + LogManager.method_info(f"数据是:{result}", "关注打招呼", udid) + + state = result.get("state", 0) if not state: - LogManager.method_info(f"当前主播的状态是:{state} 不通行,取出数据移到列表尾部 继续下一个", "关注打招呼", udid) + LogManager.method_info(f"当前主播的状态是:{state} 不通行,取出数据移到列表尾部 继续下一个", "关注打招呼", + udid) AiUtils.pop_aclist_first(mode="move") continue @@ -337,7 +342,7 @@ class ScriptManager(): time.sleep(30) continue - aid = anchor["anchorId"] + aid = anchor.get("anchorId", "") anchorCountry = anchor.get("country", "") LogManager.method_info(f"主播的数据,用户名:{aid},国家:{anchorCountry}", "关注打招呼", udid) diff --git a/script/__pycache__/ScriptManager.cpython-312.pyc b/script/__pycache__/ScriptManager.cpython-312.pyc index c6c2a23..b3eb96e 100644 Binary files a/script/__pycache__/ScriptManager.cpython-312.pyc and b/script/__pycache__/ScriptManager.cpython-312.pyc differ diff --git a/tidevice.spec b/tidevice.spec deleted file mode 100644 index 2474907..0000000 --- a/tidevice.spec +++ /dev/null @@ -1,45 +0,0 @@ -# -*- mode: python ; coding: utf-8 -*- -from PyInstaller.utils.hooks import collect_all - -datas = [('C:\\Users\\milk\\AppData\\Local\\Programs\\Python\\Python312\\Lib\\site-packages\\tidevice', 'tidevice')] -binaries = [] -hiddenimports = ['tidevice._proto', 'tidevice._instruments', 'tidevice._usbmux', 'tidevice._wdaproxy'] -tmp_ret = collect_all('tidevice') -datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2] - - -a = Analysis( - ['tidevice_entry.py'], - pathex=[], - binaries=binaries, - datas=datas, - hiddenimports=hiddenimports, - hookspath=[], - hooksconfig={}, - runtime_hooks=[], - excludes=[], - noarchive=False, - optimize=0, -) -pyz = PYZ(a.pure) - -exe = EXE( - pyz, - a.scripts, - a.binaries, - a.datas, - [], - name='tidevice', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - upx_exclude=[], - runtime_tmpdir=None, - console=False, - disable_windowed_traceback=False, - argv_emulation=False, - target_arch=None, - codesign_identity=None, - entitlements_file=None, -)