mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 11:20:43 +00:00
被控端 - 修复 MTU 问题:夹 MSS + 路径 MTU 探测(公网可用率 48% -> 100%) - 复用 HTTP 连接(免掉每次新建 TLS 的 30% 握手失败) - 每分钟回头找局域网,自动切回快 400 倍的路径 - 画面心跳帧:静止时省流量,客户端仍知道流是活的 - 锁屏时给出可操作的提示 手表端 - 内置 GTS Root R4 / GlobalSign Root CA,修 SSLHandshakeException - 连接错误翻译成人话(证书/时间/解析/超时分别提示) - 经中转连上后用服务器报的地址刷新已配对记录 - 新增局域网连接页面、服务器延迟检测 服务器端 - 支持 chunked 请求体(修每 16 秒一次的连接错乱与大面积 502) - 网络调优脚本 net-tune.sh(开机自动应用) - 管理页:批量删除、网络体检、下载区 - 隧道改 HTTP/2 + 双连接 文档 - 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
175 lines
6.6 KiB
Python
175 lines
6.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""手表端:音色选择 + 播放电脑音乐(用真实的 client.call / sendCommand)。"""
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
MAIN = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\android\src"
|
|
r"\com\lanremote\watch\MainActivity.java")
|
|
|
|
OLD_ROW = ''' addRow(grid,
|
|
action("语音播报", new Runnable() {
|
|
public void run() { promptSay(); }
|
|
}),
|
|
action("弹通知", new Runnable() {
|
|
public void run() { promptNotify(); }
|
|
}));
|
|
'''
|
|
|
|
NEW_ROW = ''' addRow(grid,
|
|
action("语音播报", new Runnable() {
|
|
public void run() { promptSay(); }
|
|
}),
|
|
action("音色", new Runnable() {
|
|
public void run() { pickVoice(); }
|
|
}));
|
|
|
|
addRow(grid,
|
|
action("电脑音乐", new Runnable() {
|
|
public void run() { pickLocalAudio(); }
|
|
}),
|
|
action("弹通知", new Runnable() {
|
|
public void run() { promptNotify(); }
|
|
}));
|
|
'''
|
|
|
|
ANCHOR = ''' private void promptSay() {'''
|
|
|
|
NEW_METHODS = ''' /** 选择电脑上的 TTS 音色。 */
|
|
private void pickVoice() {
|
|
appendLog("正在获取电脑音色…");
|
|
io.execute(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
final Map<String, Object> reply =
|
|
client.call(Json.obj("cmd", "voice_list"), 12000);
|
|
final List<String> voices = stringList(reply, "voices");
|
|
ui.post(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (voices.isEmpty()) {
|
|
toast("电脑上没读到音色,或没连上");
|
|
return;
|
|
}
|
|
List<String> labels = new ArrayList<String>();
|
|
labels.add("系统默认");
|
|
labels.addAll(voices);
|
|
showChooser("选择播报音色", labels, new Chooser() {
|
|
@Override
|
|
public void onPick(int index) {
|
|
String chosen = index == 0 ? "" : voices.get(index - 1);
|
|
sendCommand(Json.obj("cmd", "set_voice",
|
|
"voice", chosen), "设置音色");
|
|
}
|
|
});
|
|
}
|
|
});
|
|
} catch (final IOException e) {
|
|
postError("获取音色", e);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/** 选一个电脑上的音频文件直接播放。 */
|
|
private void pickLocalAudio() {
|
|
appendLog("正在获取电脑音乐…");
|
|
io.execute(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
final Map<String, Object> reply =
|
|
client.call(Json.obj("cmd", "audio_list"), 15000);
|
|
final List<String> names = stringList(reply, "names");
|
|
final List<String> paths = stringList(reply, "paths");
|
|
ui.post(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (names.isEmpty() || names.size() != paths.size()) {
|
|
toast("电脑音乐目录里没有音频文件");
|
|
return;
|
|
}
|
|
showChooser("选择要播放的音乐", names, new Chooser() {
|
|
@Override
|
|
public void onPick(int index) {
|
|
sendCommand(Json.obj("cmd", "play_local",
|
|
"path", paths.get(index)),
|
|
"播放 " + names.get(index));
|
|
}
|
|
});
|
|
}
|
|
});
|
|
} catch (final IOException e) {
|
|
postError("获取音乐列表", e);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/** 把回复里的字符串数组取出来。 */
|
|
@SuppressWarnings("unchecked")
|
|
private static List<String> stringList(Map<String, Object> reply, String key) {
|
|
List<String> out = new ArrayList<String>();
|
|
try {
|
|
Object raw = reply == null ? null : reply.get(key);
|
|
if (raw instanceof List) {
|
|
for (Object item : (List<Object>) raw) {
|
|
if (item != null) {
|
|
out.add(String.valueOf(item));
|
|
}
|
|
}
|
|
}
|
|
} catch (Exception ignored) {
|
|
// 结构不对就返回空
|
|
}
|
|
return out;
|
|
}
|
|
|
|
private void promptSay() {'''
|
|
|
|
DIALOG_ANCHOR = ''' private Button bigButton(String text, int color, float sizeSp) {'''
|
|
|
|
DIALOG = ''' /** 简单的列表选择框。 */
|
|
private interface Chooser {
|
|
void onPick(int index);
|
|
}
|
|
|
|
private void showChooser(String title, List<String> items, final Chooser chooser) {
|
|
final String[] array = items.toArray(new String[0]);
|
|
new AlertDialog.Builder(this)
|
|
.setTitle(title)
|
|
.setItems(array, new android.content.DialogInterface.OnClickListener() {
|
|
@Override
|
|
public void onClick(android.content.DialogInterface dialog, int which) {
|
|
chooser.onPick(which);
|
|
}
|
|
})
|
|
.setNegativeButton("取消", null)
|
|
.show();
|
|
}
|
|
|
|
private Button bigButton(String text, int color, float sizeSp) {'''
|
|
|
|
|
|
def main() -> int:
|
|
text = MAIN.read_text(encoding="utf-8")
|
|
ok = True
|
|
for old, new, tag in ((OLD_ROW, NEW_ROW, "按钮"),
|
|
(ANCHOR, NEW_METHODS, "处理方法"),
|
|
(DIALOG_ANCHOR, DIALOG, "选择框")):
|
|
if old not in text:
|
|
print(f" [失败] {tag} 锚点未匹配")
|
|
ok = False
|
|
else:
|
|
text = text.replace(old, new, 1)
|
|
print(f" {tag}: OK")
|
|
if ok:
|
|
MAIN.write_text(text, encoding="utf-8")
|
|
return 0 if ok else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|