ykxmz 1.5.0:修复手表端 TLS 证书校验 + MTU 修复网络稳定性

被控端
- 修复 MTU 问题:夹 MSS + 路径 MTU 探测(公网可用率 48% -> 100%)
- 复用 HTTP 连接(免掉每次新建 TLS 的 30% 握手失败)
- 每分钟回头找局域网,自动切回快 400 倍的路径
- 画面心跳帧:静止时省流量,客户端仍知道流是活的
- 锁屏时给出可操作的提示

手表端
- 内置 GTS Root R4 / GlobalSign Root CA,修 SSLHandshakeException
- 连接错误翻译成人话(证书/时间/解析/超时分别提示)
- 经中转连上后用服务器报的地址刷新已配对记录
- 新增局域网连接页面、服务器延迟检测

服务器端
- 支持 chunked 请求体(修每 16 秒一次的连接错乱与大面积 502)
- 网络调优脚本 net-tune.sh(开机自动应用)
- 管理页:批量删除、网络体检、下载区
- 隧道改 HTTP/2 + 双连接

文档
- 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
This commit is contained in:
xmz7891
2026-10-06 19:01:05 +08:00
commit b62ac865ea
3195 changed files with 203292 additions and 0 deletions
+297
View File
@@ -0,0 +1,297 @@
# -*- coding: utf-8 -*-
"""重做电脑端界面(保留浅色 + 简洁的设计理念,提升观感)+ 两个新入口。
改动:
* 顶栏:主色竖条 + 粗体标题 + 圆角风格的状态徽标(有底色,不是干巴巴一行字)
* 配对卡片:更大留白、更清晰的层次、副标题
* 底栏:接收目录 / 连不上? / 设置 / 退出
* 新增 open_selfcheck():一键拉起网络自检的控制台窗口
* 新增 open_settings():投图窗口标题、TTS 音色与语速、本机音乐目录
"""
from __future__ import annotations
import sys
from pathlib import Path
UI = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\windows"
r"\lanremote\ui.py")
OLD_BUILD_START = ''' def _build(self) -> None:
pad = {"padx": 14}
head = tk.Frame(self.root, bg=BG)
head.pack(fill="x", pady=(12, 4), **pad)
tk.Label(head, text=APP_NAME, bg=BG, fg=FG, font=FONT_TITLE).pack(side="left")
self.lbl_state = tk.Label(head, text="启动中", bg=BG, fg=DIM, font=FONT_SMALL)
self.lbl_state.pack(side="right")
card = tk.Frame(self.root, bg=CARD, highlightthickness=1,
highlightbackground=BORDER)
card.pack(fill="x", pady=6, **pad)
tk.Label(card, text="在手表上输入这串数字", bg=CARD, fg=DIM,
font=FONT_SMALL).pack(pady=(10, 0))
self.lbl_code = tk.Label(card, text="------", bg=CARD, fg=ACCENT, font=FONT_BIG)
self.lbl_code.pack(pady=(0, 2))
self.lbl_code.bind("<Double-Button-1>", lambda _e: self.copy_code())
row = tk.Frame(card, bg=CARD)
row.pack(pady=(0, 10))
self._btn(row, "换一组", self.new_code, width=8)
self._btn(row, "复制", self.copy_code, width=6)
'''
NEW_BUILD_START = ''' def _build(self) -> None:
pad = {"padx": 14}
# ---- 顶栏:主色竖条 + 标题 + 状态徽标 ----
head = tk.Frame(self.root, bg=BG)
head.pack(fill="x", pady=(12, 8), **pad)
tk.Frame(head, bg=ACCENT, width=4, height=18).pack(side="left", padx=(0, 8))
tk.Label(head, text=APP_NAME, bg=BG, fg=FG,
font=("Microsoft YaHei UI", 12, "bold")).pack(side="left")
self.state_badge = tk.Frame(head, bg="#eef1f4")
self.state_badge.pack(side="right")
self.lbl_state = tk.Label(self.state_badge, text="● 启动中", bg="#eef1f4",
fg=DIM, font=("Microsoft YaHei UI", 9, "bold"),
padx=10, pady=3)
self.lbl_state.pack()
# ---- 配对码卡片 ----
card = tk.Frame(self.root, bg=CARD, highlightthickness=1,
highlightbackground=BORDER)
card.pack(fill="x", pady=(0, 8), **pad)
tk.Label(card, text="在手表上输入这串数字", bg=CARD, fg=DIM,
font=FONT_SMALL).pack(pady=(14, 0))
self.lbl_code = tk.Label(card, text="------", bg=CARD, fg=ACCENT,
font=FONT_BIG)
self.lbl_code.pack(pady=(2, 0))
self.lbl_code.bind("<Double-Button-1>", lambda _e: self.copy_code())
tk.Label(card, text="双击数字也能复制", bg=CARD, fg="#9aa4af",
font=("Microsoft YaHei UI", 8)).pack()
row = tk.Frame(card, bg=CARD)
row.pack(pady=(12, 16))
self._btn(row, "换一组", self.new_code, width=9)
self._btn(row, "复制", self.copy_code, width=7, last=True)
'''
OLD_FOOT = ''' foot = tk.Frame(self.root, bg=BG)
foot.pack(fill="x", side="bottom", pady=(0, 6), **pad)
self._btn(foot, "打开接收目录", self.open_received, width=12)
self._btn(foot, "退出", self.quit_app, width=7, danger=True)
tk.Label(self.root,
text="关掉窗口后仍在后台运行\\n再次双击图标可找回本窗口",
bg=BG, fg=DIM, font=("Microsoft YaHei UI", 8),
anchor="w", justify="left").pack(fill="x", side="bottom",
padx=14, pady=(0, 8))
'''
NEW_FOOT = ''' foot = tk.Frame(self.root, bg=BG)
foot.pack(fill="x", side="bottom", pady=(0, 6), **pad)
self._btn(foot, "接收目录", self.open_received, width=9)
self._btn(foot, "连不上?", self.open_selfcheck, width=9)
self._btn(foot, "设置", self.open_settings, width=6)
self._btn(foot, "退出", self.quit_app, width=5, danger=True, last=True)
tk.Label(self.root,
text="关掉窗口后仍在后台运行,再次双击可找回",
bg=BG, fg=DIM, font=("Microsoft YaHei UI", 8),
anchor="w", justify="left").pack(fill="x", side="bottom",
padx=14, pady=(0, 8))
'''
OLD_BTN = ''' def _btn(self, parent, text, command, width=10, danger=False):
bg = "#ffeef0" if danger else "#eaeef2"
hover = "#ffdce0" if danger else "#dfe4ea"
btn = tk.Button(parent, text=text, command=command, width=width,
bg=bg, fg=(DANGER if danger else FG), activebackground=hover,
activeforeground=(DANGER if danger else FG), highlightthickness=1,
highlightbackground=BORDER, bd=0,
relief="flat", font=FONT_UI, cursor="hand2", padx=4, pady=4)
btn.pack(side="left", padx=(0, 8))
'''
NEW_BTN = ''' def _btn(self, parent, text, command, width=10, danger=False, last=False):
bg = "#ffeef0" if danger else "#eaeef2"
hover = "#ffdce0" if danger else "#dfe4ea"
btn = tk.Button(parent, text=text, command=command, width=width,
bg=bg, fg=(DANGER if danger else FG), activebackground=hover,
activeforeground=(DANGER if danger else FG), highlightthickness=1,
highlightbackground=BORDER, bd=0,
relief="flat", font=FONT_UI, cursor="hand2", padx=4, pady=5)
btn.pack(side="left", padx=(0, 0 if last else 8))
'''
OLD_REFRESH_STATE = ''' if sharing:
self.lbl_state.configure(text="屏幕共享中", fg=DANGER)
elif connected:
self.lbl_state.configure(text="已连接", fg=OK)
else:
self.lbl_state.configure(text="运行中", fg=OK)
'''
NEW_REFRESH_STATE = ''' if sharing:
self.set_badge("● 屏幕共享中", DANGER, "#ffeef0")
elif connected:
self.set_badge("● 已连接", OK, "#e6f4ea")
else:
self.set_badge("● 待连接", DIM, "#eef1f4")
'''
NEW_METHODS = ''' # ---- 状态徽标 ----
def set_badge(self, text: str, color: str, soft: str) -> None:
try:
self.state_badge.configure(bg=soft)
self.lbl_state.configure(text=text, bg=soft, fg=color)
except tk.TclError:
pass
# ---- 连不上?直接拉起网络自检 ----
def open_selfcheck(self) -> None:
"""连不上时一键启动网络自检(开一个控制台窗口显示实时结果)。"""
import subprocess
from .config import app_dir
bat = app_dir() / "网络自检.bat"
if not bat.is_file():
self.show_message("没找到 网络自检.bat")
return
try:
flags = getattr(subprocess, "CREATE_NEW_CONSOLE", 0)
subprocess.Popen(["cmd", "/c", str(bat)], creationflags=flags)
except Exception as exc: # noqa: BLE001
self.show_message(f"启动自检失败:{exc}")
return
self.show_message("已打开网络自检窗口")
# ---- 设置 ----
def open_settings(self) -> None:
"""设置对话框:投图窗口标题 / TTS 音色与语速 / 本机音乐目录。"""
from .actions import Actions
win = tk.Toplevel(self.root)
win.title("设置")
win.configure(bg=BG)
win.resizable(False, False)
def row_label(text, hint=""):
box = tk.Frame(win, bg=BG)
box.pack(fill="x", padx=16, pady=(10, 2))
tk.Label(box, text=text, bg=BG, fg=FG, font=FONT_UI,
anchor="w").pack(side="left")
if hint:
tk.Label(box, text=hint, bg=BG, fg=DIM,
font=("Microsoft YaHei UI", 8)).pack(side="left", padx=(6, 0))
def entry(initial, width=34):
box = tk.Frame(win, bg=BG)
box.pack(fill="x", padx=16)
ent = tk.Entry(box, width=width, bg=CARD, fg=FG, relief="flat",
font=FONT_UI, highlightthickness=1,
highlightbackground=BORDER, highlightcolor=ACCENT)
ent.pack(fill="x", ipady=5)
ent.insert(0, initial)
return ent
# 投图窗口标题
row_label("投图窗口标题", "支持 {name}")
ent_title = entry(str(self.store.get("image_window_title") or ""))
# TTS 音色
row_label("语音播报音色")
voice_box = tk.Frame(win, bg=BG)
voice_box.pack(fill="x", padx=16)
voices = []
try:
voices = Actions(self, self.store).list_voices()
except Exception: # noqa: BLE001
voices = []
current = str(self.store.get("tts_voice") or "")
options = ["系统默认"] + voices
var_voice = tk.StringVar(value=current if current in voices else "系统默认")
opt = tk.OptionMenu(voice_box, var_voice, *options)
opt.configure(bg=CARD, fg=FG, activebackground="#eaeef2",
activeforeground=FG, relief="flat", highlightthickness=1,
highlightbackground=BORDER, font=FONT_SMALL, width=26,
anchor="w", cursor="hand2", padx=4)
try:
opt["menu"].configure(bg=CARD, fg=FG, font=FONT_SMALL,
activebackground="#eaeef2", bd=0)
except tk.TclError:
pass
opt.pack(side="left")
# 语速
row_label("语速", "-10 慢 … 10 快")
ent_rate = entry(str(self.store.get("tts_rate", 0)), width=8)
# 本机音乐目录
row_label("本机音乐目录", "留空=自动找 音乐 / Music / Downloads")
ent_mp3 = entry(str(self.store.get("mp3_dir") or ""))
def save():
self.store.set("image_window_title", ent_title.get().strip())
chosen = var_voice.get()
self.store.set("tts_voice", "" if chosen == "系统默认" else chosen)
raw = ent_rate.get().strip()
try:
rate = max(-10, min(10, int(raw)))
except ValueError:
rate = 0
self.store.set("tts_rate", rate)
self.store.set("mp3_dir", ent_mp3.get().strip())
self.log(f"设置已保存(音色={chosen},语速={rate})")
win.destroy()
self.show_message("设置已保存")
buttons = tk.Frame(win, bg=BG)
buttons.pack(fill="x", padx=16, pady=(16, 16))
self._btn(buttons, "保存", save, width=8)
self._btn(buttons, "取消", win.destroy, width=6, last=True)
self.center_window(win)
def _build(self) -> None:
'''
def main() -> int:
text = UI.read_text(encoding="utf-8")
ok = True
for old, new, tag in ((OLD_BUILD_START, NEW_BUILD_START, "顶栏+卡片"),
(OLD_FOOT, NEW_FOOT, "底栏"),
(OLD_BTN, NEW_BTN, "按钮 last"),
(OLD_REFRESH_STATE, NEW_REFRESH_STATE, "状态徽标")):
if old not in text:
print(f" [失败] {tag} 锚点未匹配")
ok = False
else:
text = text.replace(old, new, 1)
print(f" {tag}: OK")
if not ok:
return 1
# 插入新方法(放在 _build 之前)
text = text.replace(" def _build(self) -> None:",
NEW_METHODS, 1)
UI.write_text(text, encoding="utf-8")
print(" 新方法: OK")
print("\n语法检查:")
import ast
try:
ast.parse(UI.read_text(encoding="utf-8"))
print(" ui.py: OK")
except SyntaxError as exc:
print(f" ui.py: 语法错误 {exc}")
return 1
return 0
if __name__ == "__main__":
sys.exit(main())