@@ -7,13 +7,16 @@ import time
from pathlib import Path
from queue import Queue
from typing import Any , Dict , List
import anyio
from quart import Quart
from quart_cors import cors
from Entity import Variables
from Utils . AiUtils import AiUtils
from Utils . IOSAIStorage import IOSAIStorage
from Utils . LogManager import LogManager
import wda
from flask import Flask , request
from flask_cors import CORS
from quart import Quart , request , g
from Entity . ResultData import ResultData
from Utils . ControlUtils import ControlUtils
from Utils . ThreadManager import ThreadManager
@@ -29,8 +32,9 @@ for name in ('werkzeug', 'werkzeug.serving'):
log . propagate = False
log . handlers . clear ( )
app = Flask ( __name__ )
CORS ( app )
app = Quart ( __name__ ) # ⭐ 这里用 Quart, 而不是 Flask
app = cors ( app , allow_origin = " * " ) # 允许所有来源跨域
app . config [ ' JSON_AS_ASCII ' ] = False # Flask jsonify 不转义中文/emoji
app . config [ ' JSONIFY_MIMETYPE ' ] = " application/json; charset=utf-8 "
@@ -277,9 +281,27 @@ def bootstrap_server_side_effects():
def get_app ( ) :
return app
@app.before_request
def _log_request_start ( ) :
g . _start_ts = time . time ( )
LogManager . info (
text = f " [HTTP] START { request . method } { request . path } " ,
udid = " flask "
)
@app.after_request
def _log_request_end ( response ) :
cost = time . time ( ) - getattr ( g , " _start_ts " , time . time ( ) )
LogManager . info (
text = f " [HTTP] END { request . method } { request . path } { response . status_code } in { cost : .3f } s " ,
udid = " flask "
)
return response
# ============ API 路由 ============
@app.route ( ' /deviceList ' , methods = [ ' GET ' ] )
def deviceList ( ) :
async def deviceList ( ) :
global _last_device_count , change_version
global _last_nonempty_snapshot , _last_snapshot_ts , _STICKY_TTL_SEC
global _empty_logged , _recovered_logged
@@ -315,23 +337,23 @@ def deviceList():
return ResultData ( data = [ ] ) . toJson ( )
@app.route ( ' /passToken ' , methods = [ ' POST ' ] )
def passToken ( ) :
data = request . get_json ( )
async def passToken ( ) :
data = await request . get_json ( )
print ( json . dumps ( data ) )
return ResultData ( data = " " ) . toJson ( )
# 获取设备应用列表
@app.route ( ' /deviceAppList ' , methods = [ ' POST ' ] )
def deviceAppList ( ) :
param = request . get_json ( )
async def deviceAppList ( ) :
param = await request . get_json ( )
udid = param [ " udid " ]
apps = ControlUtils . getDeviceAppList ( udid )
return ResultData ( data = apps ) . toJson ( )
# 打开指定app
@app.route ( ' /launchApp ' , methods = [ ' POST ' ] )
def launchApp ( ) :
body = request . get_json ( )
async def launchApp ( ) :
body = await request . get_json ( )
udid = body . get ( " udid " )
bundleId = body . get ( " bundleId " )
t = wda . USBClient ( udid , wdaFunctionPort )
@@ -340,8 +362,8 @@ def launchApp():
# 回到首页
@app.route ( ' /toHome ' , methods = [ ' POST ' ] )
def toHome ( ) :
body = request . get_json ( )
async def toHome ( ) :
body = await request . get_json ( )
udid = body . get ( " udid " )
client = wda . USBClient ( udid , wdaFunctionPort )
client . home ( )
@@ -349,8 +371,8 @@ def toHome():
# 点击事件
@app.route ( ' /tapAction ' , methods = [ ' POST ' ] )
def tapAction ( ) :
body = request . get_json ( )
async def tapAction ( ) :
body = await request . get_json ( )
udid = body . get ( " udid " )
client = wda . USBClient ( udid , wdaFunctionPort )
print ( " ----------------------- " )
@@ -365,8 +387,8 @@ def tapAction():
# 拖拽事件
@app.route ( ' /swipeAction ' , methods = [ ' POST ' ] )
def swipeAction ( ) :
body = request . get_json ( )
async def swipeAction ( ) :
body = await request . get_json ( )
udid = body . get ( " udid " )
duration = body . get ( " duration " ) # 时长
sx = body . get ( " sx " ) # 起始X点
@@ -383,8 +405,8 @@ def swipeAction():
# 长按事件
@app.route ( ' /longPressAction ' , methods = [ ' POST ' ] )
def longPressAction ( ) :
body = request . get_json ( )
async def longPressAction ( ) :
body = await request . get_json ( )
udid = body . get ( " udid " )
x = body . get ( " x " )
y = body . get ( " y " )
@@ -396,8 +418,8 @@ def longPressAction():
# 养号
@app.route ( ' /growAccount ' , methods = [ ' POST ' ] )
def growAccount ( ) :
body = request . get_json ( )
async def growAccount ( ) :
body = await request . get_json ( )
udid = body . get ( " udid " )
Variables . commentList = body . get ( " comment " )
isComment = body . get ( " isComment " )
@@ -412,8 +434,8 @@ def growAccount():
# 观看直播
@app.route ( " /watchLiveForGrowth " , methods = [ ' POST ' ] )
def watchLiveForGrowth ( ) :
body = request . get_json ( )
async def watchLiveForGrowth ( ) :
body = await request . get_json ( )
udid = body . get ( " udid " )
manager = ScriptManager ( )
event = threading . Event ( )
@@ -424,8 +446,8 @@ def watchLiveForGrowth():
# 停止脚本
@app.route ( " /stopScript " , methods = [ ' POST ' ] )
def stopScript ( ) :
body = request . get_json ( )
async def stopScript ( ) :
body = await request . get_json ( )
udid = body . get ( " udid " )
LogManager . method_info ( f " 接口收到 /stopScript udid= { udid } " , method = " task " )
code , msg = ThreadManager . stop ( udid )
@@ -433,10 +455,10 @@ def stopScript():
# 关注打招呼
@app.route ( ' /passAnchorData ' , methods = [ ' POST ' ] )
def passAnchorData ( ) :
async def passAnchorData ( ) :
try :
LogManager . method_info ( " 关注打招呼 " , " 关注打招呼 " )
data : Dict [ str , Any ] = request . get_json ( )
data : Dict [ str , Any ] = await request . get_json ( )
# 设备列表
idList = data . get ( " deviceList " , [ ] )
# 主播列表
@@ -469,10 +491,10 @@ def passAnchorData():
return ResultData ( data = " " , code = 1001 ) . toJson ( )
@app.route ( ' /followAndGreetUnion ' , methods = [ ' POST ' ] )
def followAndGreetUnion ( ) :
async def followAndGreetUnion ( ) :
try :
LogManager . method_info ( " 关注打招呼 " , " 关注打招呼(联盟号) " )
data : Dict [ str , Any ] = request . get_json ( )
data : Dict [ str , Any ] = await request . get_json ( )
# 设备列表
idList = data . get ( " deviceList " , [ ] )
# 主播列表
@@ -510,20 +532,20 @@ def followAndGreetUnion():
# 获取私信数据
@app.route ( " /getPrologueList " , methods = [ ' GET ' ] )
def getPrologueList ( ) :
async def getPrologueList ( ) :
import Entity . Variables as Variables
return ResultData ( data = Variables . prologueList ) . toJson ( )
# 添加临时数据
# 批量追加主播到 JSON 文件
@app.route ( " /addTempAnchorData " , methods = [ ' POST ' ] )
def addTempAnchorData ( ) :
async def addTempAnchorData ( ) :
"""
请求体支持:
- 单个对象: { " anchorId " : " xxx " , " country " : " CN " }
- 对象数组:[ { " anchorId " : " xxx " , " country " : " CN " }, { " anchorId " : " yyy " , " country " : " US " }]
"""
data = request . get_json ( )
data = await request . get_json ( )
if not data :
return ResultData ( code = 400 , message = " 请求数据为空 " ) . toJson ( )
# 追加到 JSON 文件
@@ -532,8 +554,8 @@ def addTempAnchorData():
# 获取当前屏幕上的聊天信息
@app.route ( " /getChatTextInfo " , methods = [ ' POST ' ] )
def getChatTextInfo ( ) :
data = request . get_json ( )
async def getChatTextInfo ( ) :
data = await request . get_json ( )
udid = data . get ( " udid " )
client = wda . USBClient ( udid , wdaFunctionPort )
session = client . session ( )
@@ -578,9 +600,9 @@ def getChatTextInfo():
# 监控消息
@app.route ( " /replyMessages " , methods = [ ' POST ' ] )
def monitorMessages ( ) :
async def monitorMessages ( ) :
LogManager . method_info ( " 开始监控消息,监控消息脚本启动 " , " 监控消息 " )
body = request . get_json ( )
body = await request . get_json ( )
udid = body . get ( " udid " )
# Variables.commentList = body.get("comment")
@@ -594,8 +616,8 @@ def monitorMessages():
# 上传日志
@app.route ( " /setLoginInfo " , methods = [ ' POST ' ] )
def upLoadLogLogs ( ) :
data = request . get_json ( ) # 解析 JSON
async def upLoadLogLogs ( ) :
data = await request . get_json ( ) # 解析 JSON
token = data . get ( " token " )
userId = data . get ( " userId " )
tenantId = data . get ( " tenantId " )
@@ -607,7 +629,7 @@ def upLoadLogLogs():
# 获取当前的主播列表数据
@app.route ( " /anchorList " , methods = [ ' POST ' ] )
def queryAnchorList ( ) :
async def queryAnchorList ( ) :
# 项目根目录(当前文件在 infos 下,回退两层到根目录)
root_dir = Path ( __file__ ) . resolve ( ) . parent . parent
file_path = root_dir / " data " / " acList.json "
@@ -624,12 +646,12 @@ def queryAnchorList():
# 修改当前的主播列表数据
@app.route ( " /updateAnchorList " , methods = [ ' POST ' ] )
def updateAnchorList ( ) :
async def updateAnchorList ( ) :
"""
invitationType: 1 普票 2 金票
state: 1 通行(True) / 0 不通行(False)
"""
data = request . get_json ( force = True , silent = True ) or { }
data = await request . get_json ( force = True , silent = True ) or { }
invitationType = data . get ( " invitationType " )
state = bool ( data . get ( " state " ) ) # 转成布尔
@@ -679,16 +701,16 @@ def updateAnchorList():
# 删除主播
@app.route ( " /deleteAnchorWithIds " , methods = [ ' POST ' ] )
def deleteAnchorWithIds ( ) :
ls : list [ dict ] = request . get_json ( ) # [{"anchorId": "xxx"}, ...]
async def deleteAnchorWithIds ( ) :
ls : list [ dict ] = await request . get_json ( ) # [{"anchorId": "xxx"}, ...]
ids = [ d . get ( " anchorId " ) for d in ls if d . get ( " anchorId " ) ]
deleted = AiUtils . delete_anchors_by_ids ( ids )
return ResultData ( data = { " deleted " : deleted } ) . toJson ( )
# 配置ai人设
@app.route ( " /aiConfig " , methods = [ ' POST ' ] )
def aiConfig ( ) :
data = request . get_json ( )
async def aiConfig ( ) :
data = await request . get_json ( )
agentName = data . get ( " agentName " )
guildName = data . get ( " guildName " )
contactTool = data . get ( " contactTool " )
@@ -725,14 +747,14 @@ def aiConfig():
# 查询主播聊天发送的最后一条信息
@app.route ( " /select_last_message " , methods = [ ' GET ' ] )
def select_last_message ( ) :
async def select_last_message ( ) :
data = JsonUtils . query_all_json_items ( )
return ResultData ( data = data ) . toJson ( )
# 修改消息(已读改成未读)
@app.route ( " /update_last_message " , methods = [ ' POST ' ] )
def update_last_message ( ) :
data = request . get_json ( ) # 解析 JSON
async def update_last_message ( ) :
data = await request . get_json ( ) # 解析 JSON
sender = data . get ( " sender " )
udid = data . get ( " device " )
text = data . get ( " text " )
@@ -749,8 +771,8 @@ def update_last_message():
# 删除已读消息
@app.route ( " /delete_last_message " , methods = [ ' POST ' ] )
def delete_last_message ( ) :
data = request . get_json ( ) # 解析 JSON
async def delete_last_message ( ) :
data = await request . get_json ( ) # 解析 JSON
sender = data . get ( " sender " )
udid = data . get ( " device " )
text = data . get ( " text " )
@@ -767,15 +789,15 @@ def delete_last_message():
# 停止所有任务
@app.route ( " /stopAllTask " , methods = [ ' POST ' ] )
def stopAllTask ( ) :
idList = request . get_json ( )
async def stopAllTask ( ) :
idList = await request . get_json ( )
code , msg , data = ThreadManager . batch_stop ( idList )
return ResultData ( code , data , msg ) . toJson ( )
# 切换账号
@app.route ( ' /changeAccount ' , methods = [ ' POST ' ] )
def changeAccount ( ) :
body = request . get_json ( )
async def changeAccount ( ) :
body = await request . get_json ( )
udid = body . get ( " udid " )
if not udid :
return ResultData ( data = " " , code = 400 , message = " 缺少 udid " ) . toJson ( )
@@ -792,12 +814,16 @@ def changeAccount():
# 查看设备网络状态
@app.route ( ' /getDeviceNetStatus ' , methods = [ ' POST ' ] )
def getDeviceNetStatus ( ) :
body = request . get_json ( )
async def getDeviceNetStatus ( ) :
body = await request . get_json ( )
udid = body . get ( " udid " )
client = wda . USBClient ( udid , wdaFunctionPort )
r = client . getNetWorkStatus ( )
value = r . get ( " value " )
# 同步且超级慢的逻辑 → 丢到线程池,不阻塞事件循环
def _work ( ) :
client = wda . USBClient ( udid , wdaFunctionPort )
r = client . getNetWorkStatus ( )
return r . get ( " value " )
value = await anyio . to_thread . run_sync ( _work )
return ResultData ( data = value , code = 200 ) . toJson ( )
@app.route ( ' /test ' , methods = [ ' POST ' ] )
@@ -866,8 +892,8 @@ def getAiConfig():
# 重新开启tiktok
@app.route ( " /restartTikTok " , methods = [ ' POST ' ] )
def restartTikTok ( ) :
json = request . get_json ( )
async def restartTikTok ( ) :
json = await request . get_json ( )
udid = json . get ( " udid " )
client = wda . USBClient ( udid , wdaFunctionPort )
session = client . session ( )