修复一些问题

This commit is contained in:
2025-09-19 19:39:32 +08:00
parent 1391a2b37c
commit e94902fedf
12 changed files with 89 additions and 125 deletions

5
.gitignore vendored
View File

@@ -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
build-tidevice.bat
build.bat

36
.idea/workspace.xml generated
View File

@@ -5,37 +5,12 @@
</component>
<component name="ChangeListManager">
<list default="true" id="eceeff5e-51c1-459c-a911-d21ec090a423" name="Changes" comment="20250904-初步功能已完成">
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Module/Main.py" beforeDir="false" afterPath="$PROJECT_DIR$/Module/Main.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevice_id.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevice_id.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicebackup.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicebackup.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicebackup2.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicebackup2.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicebtlogger.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicebtlogger.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicecrashreport.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicecrashreport.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicedate.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicedate.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicedebug.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicedebug.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicedebugserverproxy.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicedebugserverproxy.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicedevmodectl.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicedevmodectl.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicediagnostics.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicediagnostics.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/ideviceenterrecovery.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/ideviceenterrecovery.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/ideviceimagemounter.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/ideviceimagemounter.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/ideviceinfo.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/ideviceinfo.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicename.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicename.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicenotificationproxy.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicenotificationproxy.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicepair.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicepair.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/ideviceprovision.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/ideviceprovision.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicerestore.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicerestore.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicescreenshot.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicescreenshot.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicesetlocation.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicesetlocation.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/idevicesyslog.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/idevicesyslog.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/inetcat.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/inetcat.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/irecovery.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/irecovery.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/libcrypto-3.dll" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/libcrypto-3.dll" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/libcurl.dll" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/libcurl.dll" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/libssl-3.dll" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/libssl-3.dll" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/plistutil.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/plistutil.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/readline.dll" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/readline.dll" afterDir="false" />
<change beforePath="$PROJECT_DIR$/resources/iproxy/tidevice.exe" beforeDir="false" afterPath="$PROJECT_DIR$/resources/iproxy/tidevice.exe" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Module/FlaskService.py" beforeDir="false" afterPath="$PROJECT_DIR$/Module/FlaskService.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Utils/AiUtils.py" beforeDir="false" afterPath="$PROJECT_DIR$/Utils/AiUtils.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Utils/ThreadManager.py" beforeDir="false" afterPath="$PROJECT_DIR$/Utils/ThreadManager.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/script/ScriptManager.py" beforeDir="false" afterPath="$PROJECT_DIR$/script/ScriptManager.py" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -102,6 +77,7 @@
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.editor.code.editing&quot;,
&quot;two.files.diff.last.used.file&quot;: &quot;E:/share/iOSAI/Module/FlaskService.py&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}</component>

View File

@@ -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():

View File

@@ -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}")

View File

@@ -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:
"""

View File

@@ -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()
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)

View File

@@ -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,
)