20250918-新增主播库功能
This commit is contained in:
118
.idea/workspace.xml
generated
118
.idea/workspace.xml
generated
@@ -6,15 +6,11 @@
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="eceeff5e-51c1-459c-a911-d21ec090a423" name="Changes" comment="20250904-初步功能已完成">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/build.bat" beforeDir="false" afterPath="$PROJECT_DIR$/build.bat" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/resources/add.png" beforeDir="false" afterPath="$PROJECT_DIR$/resources/add.png" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/resources/advertisement.png" beforeDir="false" afterPath="$PROJECT_DIR$/resources/advertisement.png" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/resources/back.png" beforeDir="false" afterPath="$PROJECT_DIR$/resources/back.png" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/resources/comment.png" beforeDir="false" afterPath="$PROJECT_DIR$/resources/comment.png" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/resources/fc18bc21951daf7be012a8a687b00a4de8b24c18/bgv.png" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/resources/icon.ico" beforeDir="false" afterPath="$PROJECT_DIR$/resources/icon.ico" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/resources/like.png" beforeDir="false" afterPath="$PROJECT_DIR$/resources/like.png" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/resources/search.png" beforeDir="false" afterPath="$PROJECT_DIR$/resources/search.png" 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/ControlUtils.py" beforeDir="false" afterPath="$PROJECT_DIR$/Utils/ControlUtils.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/script/ScriptManager.py" beforeDir="false" afterPath="$PROJECT_DIR$/script/ScriptManager.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tidevice_entry.py" beforeDir="false" afterPath="$PROJECT_DIR$/tidevice_entry.py" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -45,6 +41,9 @@
|
||||
<component name="HighlightingSettingsPerFile">
|
||||
<setting file="file://$PROJECT_DIR$/build.bat" root0="SKIP_INSPECTION" />
|
||||
</component>
|
||||
<component name="PerforceDirect.Settings">
|
||||
<option name="CHARSET" value="无" />
|
||||
</component>
|
||||
<component name="ProjectColorInfo">{
|
||||
"customColor": "",
|
||||
"associatedIndex": 5
|
||||
@@ -65,6 +64,8 @@
|
||||
"Python.123.executor": "Run",
|
||||
"Python.Main.executor": "Run",
|
||||
"Python.Test.executor": "Run",
|
||||
"Python.test (1).executor": "Run",
|
||||
"Python.test (2).executor": "Run",
|
||||
"Python.test.executor": "Run",
|
||||
"Python.tidevice_entry.executor": "Run",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
@@ -74,7 +75,7 @@
|
||||
"git-widget-placeholder": "main",
|
||||
"javascript.nodejs.core.library.configured.version": "20.17.0",
|
||||
"javascript.nodejs.core.library.typings.version": "20.17.58",
|
||||
"last_opened_file_path": "C:/Users/zhangkai/Desktop/20250916ios/iOSAI/resources",
|
||||
"last_opened_file_path": "C:/Users/zhangkai/Desktop/20250916ios/iOSAI/Utils",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
@@ -86,6 +87,8 @@
|
||||
}]]></component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="C:\Users\zhangkai\Desktop\20250916ios\iOSAI\Utils" />
|
||||
<recent name="C:\Users\zhangkai\Desktop\20250916ios\iOSAI\script" />
|
||||
<recent name="C:\Users\zhangkai\Desktop\20250916ios\iOSAI\resources" />
|
||||
</key>
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
@@ -94,29 +97,6 @@
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager" selected="Python.Main">
|
||||
<configuration name="12" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||
<module name="iOSAI" />
|
||||
<option name="ENV_FILES" value="" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/12.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="123" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||
<module name="iOSAI" />
|
||||
<option name="ENV_FILES" value="" />
|
||||
@@ -186,6 +166,52 @@
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="test (1)" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||
<module name="iOSAI" />
|
||||
<option name="ENV_FILES" value="" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="test (2)" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||
<module name="iOSAI" />
|
||||
<option name="ENV_FILES" value="" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/script" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/script/test.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="test" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||
<module name="iOSAI" />
|
||||
<option name="ENV_FILES" value="" />
|
||||
@@ -211,17 +237,19 @@
|
||||
</configuration>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Python.test (1)" />
|
||||
<item itemvalue="Python.test (2)" />
|
||||
<item itemvalue="Python.test" />
|
||||
<item itemvalue="Python.123" />
|
||||
<item itemvalue="Python.Test" />
|
||||
<item itemvalue="Python.12" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
<component name="SharedIndexes">
|
||||
<attachedChunks>
|
||||
<set>
|
||||
<option value="bundled-python-sdk-ce6832f46686-7b97d883f26b-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-252.25557.178" />
|
||||
<option value="bundled-js-predefined-1d06a55b98c1-0b3e54e931b4-JavaScript-PY-241.18034.82" />
|
||||
<option value="bundled-python-sdk-975db3bf15a3-2767605e8bc2-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-241.18034.82" />
|
||||
</set>
|
||||
</attachedChunks>
|
||||
</component>
|
||||
@@ -287,6 +315,10 @@
|
||||
<workItem from="1757506636968" duration="5910000" />
|
||||
<workItem from="1757567423145" duration="16668000" />
|
||||
<workItem from="1757998910052" duration="3676000" />
|
||||
<workItem from="1758122148569" duration="213000" />
|
||||
<workItem from="1758171936953" duration="7319000" />
|
||||
<workItem from="1758180127232" duration="653000" />
|
||||
<workItem from="1758182513694" duration="14452000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="ai 开始测试">
|
||||
<option name="closed" value="true" />
|
||||
@@ -328,7 +360,15 @@
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1757587781103</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="6" />
|
||||
<task id="LOCAL-00006" summary="20250904-初步功能已完成">
|
||||
<option name="closed" value="true" />
|
||||
<created>1758121742405</created>
|
||||
<option name="number" value="00006" />
|
||||
<option name="presentableId" value="LOCAL-00006" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1758121742405</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="7" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
@@ -357,7 +397,7 @@
|
||||
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
||||
<SUITE FILE_PATH="coverage/iOSAI$LogManager.coverage" NAME="LogManager 覆盖结果" MODIFIED="1756711414832" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/Utils" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$FlaskService.coverage" NAME="FlaskService 覆盖结果" MODIFIED="1756730187792" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/Module" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$test.coverage" NAME="test 覆盖结果" MODIFIED="1756467664420" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$test.coverage" NAME="test 覆盖结果" MODIFIED="1758183945062" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/Utils" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$windows_run.coverage" NAME="windows_run Coverage Results" MODIFIED="1756473558532" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/script" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$1352.coverage" NAME="1352 覆盖结果" MODIFIED="1757662777051" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$mac_wda_agent.coverage" NAME="mac_wda_agent Coverage Results" MODIFIED="1756473148639" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/script" />
|
||||
@@ -365,9 +405,11 @@
|
||||
<SUITE FILE_PATH="coverage/iOSAI$2111.coverage" NAME="2111 覆盖结果" MODIFIED="1757330714370" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$456.coverage" NAME="456 覆盖结果" MODIFIED="1757654671631" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$123__1_.coverage" NAME="123 (1) 覆盖结果" MODIFIED="1756897091135" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$test__1_.coverage" NAME="test (1) 覆盖结果" MODIFIED="1758193027385" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$tidevice_entry.coverage" NAME="tidevice_entry 覆盖结果" MODIFIED="1757061969626" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$ScriptManager.coverage" NAME="ScriptManager 覆盖结果" MODIFIED="1756896057801" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/script" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$Main.coverage" NAME="Main 覆盖结果" MODIFIED="1758120400301" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$Main.coverage" NAME="Main 覆盖结果" MODIFIED="1758196595807" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$123.coverage" NAME="123 覆盖结果" MODIFIED="1758115088356" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/iOSAI$test__2_.coverage" NAME="test (2) 覆盖结果" MODIFIED="1758192701951" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/script" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -92,6 +92,7 @@ def start_socket_listener():
|
||||
LogManager.error(f"[ERROR]Socket服务启动失败: {e}")
|
||||
print(f"[ERROR]Socket服务启动失败: {e}")
|
||||
|
||||
|
||||
def _handle_conn(conn: socket.socket, addr):
|
||||
try:
|
||||
with conn:
|
||||
@@ -99,16 +100,16 @@ def _handle_conn(conn: socket.socket, addr):
|
||||
buffer = ""
|
||||
while True:
|
||||
data = conn.recv(1024)
|
||||
if not data: # 对端关闭
|
||||
if not data: # 对端关闭
|
||||
break
|
||||
buffer += data.decode('utf-8', errors='ignore')
|
||||
# 2. 尝试切出完整 JSON(简单按行,也可按长度头、分隔符)
|
||||
while True:
|
||||
line, sep, buffer = buffer.partition('\n')
|
||||
if not sep: # 没找到完整行
|
||||
if not sep: # 没找到完整行
|
||||
break
|
||||
line = line.strip()
|
||||
if not line: # 空行跳过
|
||||
if not line: # 空行跳过
|
||||
continue
|
||||
try:
|
||||
obj = json.loads(line)
|
||||
@@ -275,12 +276,14 @@ def stopScript():
|
||||
@app.route('/passAnchorData', methods=['POST'])
|
||||
def passAnchorData():
|
||||
try:
|
||||
LogManager.method_info("关注打招呼","关注打招呼")
|
||||
LogManager.method_info("关注打招呼", "关注打招呼")
|
||||
data: Dict[str, Any] = request.get_json()
|
||||
# 设备列表
|
||||
idList = data.get("deviceList", [])
|
||||
# 主播列表
|
||||
acList = data.get("anchorList", [])
|
||||
LogManager.info(f"[INFO] 获取数据: {idList} {acList}")
|
||||
|
||||
AiUtils.save_aclist_flat_append(acList)
|
||||
|
||||
# 是否需要回复
|
||||
@@ -401,6 +404,70 @@ def queryAnchorList():
|
||||
return ResultData(data=data).toJson()
|
||||
|
||||
|
||||
# 修改当前的主播列表数据
|
||||
|
||||
@app.route("/updateAnchorList", methods=['POST'])
|
||||
def updateAnchorList():
|
||||
"""
|
||||
invitationType: 1 普票 2 金票
|
||||
state: 1 通行(True) / 0 不通行(False)
|
||||
"""
|
||||
data = request.get_json(force=True, silent=True) or {}
|
||||
invitationType = data.get("invitationType")
|
||||
state = bool(data.get("state")) # 转成布尔
|
||||
|
||||
# 要更新成的值
|
||||
new_status = 1 if state else 0
|
||||
|
||||
# 用工具类解析路径,避免 cwd 影响
|
||||
file_path = AiUtils._resolve_path("Module/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()
|
||||
|
||||
# 定位 anchorList
|
||||
if isinstance(doc, list):
|
||||
acList = doc
|
||||
wrapper = None
|
||||
elif isinstance(doc, dict) and isinstance(doc.get("anchorList"), list):
|
||||
acList = doc["anchorList"]
|
||||
wrapper = doc
|
||||
else:
|
||||
return ResultData(code=500, massage="文件格式不合法").toJson()
|
||||
|
||||
# 遍历并更新
|
||||
updated = 0
|
||||
for item in acList:
|
||||
if isinstance(item, dict) and item.get("invitationType") == invitationType:
|
||||
item["status"] = new_status
|
||||
updated += 1
|
||||
|
||||
# 写回(保持原始结构)
|
||||
try:
|
||||
file_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
to_write = wrapper if wrapper is not None else acList
|
||||
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()
|
||||
|
||||
if updated:
|
||||
return ResultData(data=updated, massage=f"已更新 {updated} 条记录").toJson()
|
||||
else:
|
||||
return ResultData(data=0, massage="未找到符合条件的记录").toJson()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 删除主播
|
||||
@app.route("/deleteAnchorWithIds", methods=['POST'])
|
||||
def deleteAnchorWithIds():
|
||||
|
||||
177
Utils/AiUtils.py
177
Utils/AiUtils.py
@@ -614,22 +614,55 @@ class AiUtils(object):
|
||||
with open(file_path, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
# @staticmethod
|
||||
# def _normalize_anchor_items(items):
|
||||
# """
|
||||
# 规范化输入为 [{anchorId, country}] 的列表:
|
||||
# - 允许传入:单个对象、对象列表、字符串(当 anchorId 用)
|
||||
# - 过滤不合规项
|
||||
# """
|
||||
# result = []
|
||||
# if items is None:
|
||||
# return result
|
||||
#
|
||||
# if isinstance(items, dict):
|
||||
# # 单个对象
|
||||
# aid = items.get("anchorId")
|
||||
# if aid:
|
||||
# result.append({"anchorId": str(aid), "country": items.get("country", "")})
|
||||
# return result
|
||||
#
|
||||
# if isinstance(items, list):
|
||||
# for it in items:
|
||||
# if isinstance(it, dict):
|
||||
# aid = it.get("anchorId")
|
||||
# if aid:
|
||||
# result.append({"anchorId": str(aid), "country": it.get("country", "")})
|
||||
# elif isinstance(it, str):
|
||||
# result.append({"anchorId": it, "country": ""})
|
||||
# return result
|
||||
#
|
||||
# if isinstance(items, str):
|
||||
# result.append({"anchorId": items, "country": ""})
|
||||
# return result
|
||||
|
||||
@staticmethod
|
||||
def _normalize_anchor_items(items):
|
||||
"""
|
||||
规范化输入为 [{anchorId, country}] 的列表:
|
||||
- 允许传入:单个对象、对象列表、字符串(当 anchorId 用)
|
||||
- 过滤不合规项
|
||||
规范化为 [{...}]:
|
||||
- 允许传入:单个对象、对象数组、字符串(当 anchorId 用)
|
||||
- 保留原有字段,不限制只存 anchorId/country
|
||||
- 字符串输入 → {"anchorId": xxx}
|
||||
"""
|
||||
result = []
|
||||
if items is None:
|
||||
return result
|
||||
|
||||
if isinstance(items, dict):
|
||||
# 单个对象
|
||||
aid = items.get("anchorId")
|
||||
if aid:
|
||||
result.append({"anchorId": str(aid), "country": items.get("country", "")})
|
||||
obj = dict(items) # 保留所有字段
|
||||
result.append(obj)
|
||||
return result
|
||||
|
||||
if isinstance(items, list):
|
||||
@@ -637,15 +670,17 @@ class AiUtils(object):
|
||||
if isinstance(it, dict):
|
||||
aid = it.get("anchorId")
|
||||
if aid:
|
||||
result.append({"anchorId": str(aid), "country": it.get("country", "")})
|
||||
obj = dict(it)
|
||||
result.append(obj)
|
||||
elif isinstance(it, str):
|
||||
result.append({"anchorId": it, "country": ""})
|
||||
result.append({"anchorId": it})
|
||||
return result
|
||||
|
||||
if isinstance(items, str):
|
||||
result.append({"anchorId": items, "country": ""})
|
||||
result.append({"anchorId": items})
|
||||
return result
|
||||
|
||||
|
||||
# -------- 追加(对象数组平铺追加) --------
|
||||
@classmethod
|
||||
def save_aclist_flat_append(cls, acList, filename="log/acList.json"):
|
||||
@@ -657,6 +692,8 @@ class AiUtils(object):
|
||||
{"anchorId": "tianliang30", "country": ""}
|
||||
]
|
||||
"""
|
||||
|
||||
|
||||
file_path = Path(filename)
|
||||
data = cls._read_json_list(file_path)
|
||||
|
||||
@@ -690,6 +727,97 @@ class AiUtils(object):
|
||||
cls._write_json_list(file_path, data)
|
||||
return first
|
||||
|
||||
@classmethod
|
||||
def bulk_update_anchors(cls, updates, filename="log/acList.json", case_insensitive=False):
|
||||
"""
|
||||
批量修改(文件根必须是数组,沿用 _read_json_list 的约定)
|
||||
- updates:
|
||||
dict: {"id1": {...}, "id2": {...}}
|
||||
list[dict]: [{"anchorId":"id1", ...}, {"anchorId":"id2", ...}]
|
||||
- case_insensitive: True 时用小写比较 anchorId
|
||||
返回: {"updated": <int>, "missing": [ids...], "file": "<实际命中的路径>"}
|
||||
"""
|
||||
|
||||
def norm_id(x: str) -> str:
|
||||
s = str(x).strip()
|
||||
return s.lower() if case_insensitive else s
|
||||
|
||||
# ✅ 关键:使用你已有的 _resolve_path,避免受 cwd 影响
|
||||
file_path = cls._resolve_path(filename)
|
||||
|
||||
data = cls._read_json_list(file_path)
|
||||
if not data:
|
||||
return {"updated": 0, "missing": cls._collect_all_ids(updates), "file": str(file_path)}
|
||||
|
||||
# 1) 归一化 updates -> map[normalized_id] = patch
|
||||
upd_map = {}
|
||||
raw_ids = [] # 保留原始传入 id,用于返回 missing 时回显
|
||||
if isinstance(updates, dict):
|
||||
for aid, patch in updates.items():
|
||||
if aid and isinstance(patch, dict):
|
||||
key = norm_id(aid)
|
||||
raw_ids.append(str(aid))
|
||||
patch = {k: v for k, v in patch.items() if k != "anchorId"}
|
||||
if patch:
|
||||
upd_map[key] = {**upd_map.get(key, {}), **patch}
|
||||
elif isinstance(updates, list):
|
||||
for it in updates:
|
||||
if isinstance(it, dict) and it.get("anchorId"):
|
||||
rid = str(it["anchorId"])
|
||||
key = norm_id(rid)
|
||||
raw_ids.append(rid)
|
||||
patch = {k: v for k, v in it.items() if k != "anchorId"}
|
||||
if patch:
|
||||
upd_map[key] = {**upd_map.get(key, {}), **patch}
|
||||
|
||||
if not upd_map:
|
||||
return {"updated": 0, "missing": [], "file": str(file_path)}
|
||||
|
||||
# 2) 建索引:map[normalized_id] -> item
|
||||
index = {}
|
||||
for item in data:
|
||||
if isinstance(item, dict) and "anchorId" in item:
|
||||
key = norm_id(item.get("anchorId", ""))
|
||||
if key:
|
||||
index[key] = item
|
||||
|
||||
# 3) 执行更新
|
||||
updated, seen = 0, set()
|
||||
for key, patch in upd_map.items():
|
||||
target = index.get(key)
|
||||
if target is not None:
|
||||
target.update(patch)
|
||||
updated += 1
|
||||
seen.add(key)
|
||||
|
||||
# 4) 写回
|
||||
if updated > 0:
|
||||
cls._write_json_list(file_path, data)
|
||||
|
||||
# 5) 计算未命中(按传入原始 ID 回显)
|
||||
missing = []
|
||||
for rid in raw_ids:
|
||||
if norm_id(rid) not in seen:
|
||||
missing.append(rid)
|
||||
|
||||
return {"updated": updated, "missing": missing, "file": str(file_path)}
|
||||
|
||||
@staticmethod
|
||||
def _collect_all_ids(updates):
|
||||
ids = []
|
||||
if isinstance(updates, dict):
|
||||
ids = [str(k) for k in updates.keys()]
|
||||
elif isinstance(updates, list):
|
||||
for it in updates:
|
||||
if isinstance(it, dict) and it.get("anchorId"):
|
||||
ids.append(str(it["anchorId"]))
|
||||
return ids
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def delete_anchors_by_ids(cls, ids: list[str], filename="log/acList.json") -> int:
|
||||
"""
|
||||
@@ -718,6 +846,39 @@ class AiUtils(object):
|
||||
LogManager.error(f"[delete_anchors_by_ids] 写入失败: {e}")
|
||||
return deleted
|
||||
|
||||
# -------- 查看第一个(取出但不删除) --------
|
||||
@staticmethod
|
||||
def _resolve_path(p) -> Path:
|
||||
p = Path(p)
|
||||
if p.is_absolute():
|
||||
return p
|
||||
# 以项目根目录 (iOSAI) 为基准 —— script 的上一级
|
||||
base = Path(__file__).resolve().parents[1]
|
||||
return (base / p).resolve()
|
||||
|
||||
@classmethod
|
||||
def peek_aclist_first(cls, filename="Module/log/acList.json"):
|
||||
file_path = cls._resolve_path(filename)
|
||||
if not file_path.exists():
|
||||
print(f"[peek] 文件不存在: {file_path}")
|
||||
return None
|
||||
try:
|
||||
raw = file_path.read_text(encoding="utf-8-sig").strip()
|
||||
if not raw:
|
||||
return None
|
||||
data = json.loads(raw)
|
||||
arr = data if isinstance(data, list) else data.get("anchorList") if isinstance(data, dict) else None
|
||||
if not arr:
|
||||
return None
|
||||
first = arr[0]
|
||||
norm = cls._normalize_anchor_items(first)
|
||||
return norm[0] if norm else None
|
||||
except Exception as e:
|
||||
print(f"[peek] 读取失败: {e}")
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def run_tidevice_command(udid, action, bundle_id, timeout=30):
|
||||
"""
|
||||
|
||||
@@ -189,7 +189,7 @@ class ControlUtils(object):
|
||||
def userClickProfile(cls, session, aid):
|
||||
try:
|
||||
user_btn = session.xpath("(//XCUIElementTypeButton[@name='用户' and @visible='true'])[1]")
|
||||
if user_btn:
|
||||
if user_btn.exists:
|
||||
user_btn.click()
|
||||
time.sleep(3)
|
||||
follow_btn = session.xpath(
|
||||
|
||||
@@ -61,10 +61,6 @@ class ScriptManager():
|
||||
session.appium_settings({"snapshotMaxDepth": 15})
|
||||
|
||||
# 判断当前页面上是否有推荐按钮
|
||||
# el = session(xpath='//XCUIElementTypeButton[@name="top_tabs_recomend"]')
|
||||
# node = session.xpath(
|
||||
# '//XCUIElementTypeButton[@name="top_tabs_recomend" or @name="推荐" or @label="推荐"]'
|
||||
# )
|
||||
|
||||
el = session.xpath(
|
||||
'//XCUIElementTypeButton[@name="top_tabs_recomend" or @name="推荐" or @label="推荐"]'
|
||||
@@ -278,10 +274,7 @@ class ScriptManager():
|
||||
retries = 0
|
||||
while not event.is_set():
|
||||
try:
|
||||
# AiUtils.pop_aclist_first()
|
||||
# anchor = AiUtils.pop_aclist_first()
|
||||
# if not anchor:
|
||||
# break
|
||||
|
||||
self.greetNewFollowers(udid, needReply, event)
|
||||
|
||||
except Exception as e:
|
||||
@@ -301,11 +294,13 @@ class ScriptManager():
|
||||
LogManager.method_info(f"是否要自动回复消息:{needReply}", "关注打招呼", udid)
|
||||
|
||||
# 先关闭Tik Tok
|
||||
|
||||
ControlUtils.closeTikTok(session, udid)
|
||||
time.sleep(1)
|
||||
|
||||
# 重新打开Tik Tok
|
||||
ControlUtils.openTikTok(session, udid)
|
||||
|
||||
time.sleep(3)
|
||||
LogManager.method_info(f"重启tiktok", "关注打招呼", udid)
|
||||
# 设置查找深度
|
||||
@@ -369,7 +364,6 @@ class ScriptManager():
|
||||
input.set_text(f"{aid or '暂无数据'}\n")
|
||||
|
||||
# 定位 "关注" 按钮 通过关注按钮的位置点击主播首页
|
||||
|
||||
session.appium_settings({"snapshotMaxDepth": 25})
|
||||
|
||||
try:
|
||||
@@ -499,10 +493,9 @@ class ScriptManager():
|
||||
chatInput = session.xpath("//TextView")
|
||||
if chatInput.exists:
|
||||
chatInput.click()
|
||||
chatInput.set_text(f"{msg or '暂无数据'}\n")
|
||||
time.sleep(2)
|
||||
# 发送消息
|
||||
chatInput.set_text(f"{msg or '暂无数据'}\n")
|
||||
|
||||
# input.set_text(f"{aid or '暂无数据'}\n")
|
||||
|
||||
time.sleep(1)
|
||||
@@ -603,6 +596,7 @@ class ScriptManager():
|
||||
time.sleep(3)
|
||||
continue # 重新进入 while 循环,调用 monitorMessages
|
||||
|
||||
|
||||
# 检查未读消息并回复
|
||||
def monitorMessages(self, session, udid):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user