# -*- coding: utf-8 -*- """修测试抓出来的两个真问题。 【1】_do_loop_play 崩 我上一批写的时候用了 self._lock / self._audio_alias / self._mci —— 这三个是 Actions 的属性,Features 上没有。一点就抛 AttributeError: 'Features' object has no attribute '_lock'。 顺便把它做成**真的**循环播放:Actions 加一个看门线程, 一首放完自动重放。 【2】全屏窗口没有标题 枚举窗口、任务栏、Alt+Tab 都看不到它叫什么。 给 _fullscreen_window 加 title 参数,全屏大字用文字当标题。 """ from __future__ import annotations import sys from pathlib import Path ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote") FEATURES = ROOT / "windows" / "lanremote" / "features.py" ACTIONS = ROOT / "windows" / "lanremote" / "actions.py" # ---------------- 1a. Features 那边不再碰 Actions 内部 ---------------- F_OLD = ''' def _do_loop_play(self, params) -> str: on = self._truthy(params.get("on")) with self._lock: if self._audio_alias: self._mci(f"set {self._audio_alias} time format milliseconds") self.store.set("loop_play", bool(on)) return f"循环播放:{'已开启' if on else '已关闭'}"''' F_NEW = ''' def _do_loop_play(self, params) -> str: on = self._truthy(params.get("on")) self.store.set("loop_play", bool(on)) # 真正的循环由 Actions 的看门线程负责,这里只转达开关。 # 之前直接用了 self._lock / self._audio_alias / self._mci —— # 那些是 Actions 的属性,Features 上没有,一点就崩。 setter = getattr(self.actions, "set_loop", None) if setter is not None: try: setter(bool(on)) except Exception: # noqa: BLE001 pass return f"循环播放:{'已开启' if on else '已关闭'}"''' # ---------------- 1b. Actions 实现真循环 ---------------- A_OLD = ''' self._audio_alias = alias self._audio_paused = False self._audio_name = p.name self._mci(f"play {alias}") return f"正在播放 {p.name}"''' A_NEW = ''' self._audio_alias = alias self._audio_paused = False self._audio_name = p.name self._audio_path = str(p) self._mci(f"play {alias}") return f"正在播放 {p.name}" def set_loop(self, on: bool) -> None: """开关单曲循环。开了就起一个看门线程,放完自动重放。""" self._loop = bool(on) if on and self._loop_thread is None: thread = threading.Thread(target=self._loop_watch, daemon=True, name="audio-loop") self._loop_thread = thread thread.start() def _loop_watch(self) -> None: while self._loop: time.sleep(0.6) if not self._loop: break with self._lock: alias = self._audio_alias path = self._audio_path if not alias or not path: continue if self._mci_mode(alias) != "stopped": continue # 放完了,再放一遍 try: self.play_audio(path) except Exception: # noqa: BLE001 pass self._loop_thread = None''' # ---------------- 2. 全屏窗口加标题 ---------------- W_OLD = ''' def _fullscreen_window(self, builder, seconds: float = 0.0):''' W_NEW = ''' def _fullscreen_window(self, builder, seconds: float = 0.0, title: str = ""):''' W2_OLD = ''' builder(win, close) win.bind("", close)''' W2_NEW = ''' builder(win, close) # 给窗口一个标题:不然枚举窗口、任务栏、Alt+Tab 都看不到它, # 用户也不知道电脑上那个大黑屏是什么。 try: win.title(title or "局域网遥控") except Exception: # noqa: BLE001 pass win.bind("", close)''' B_OLD = ''' self._fullscreen_window(builder) return f"已全屏显示「{text[:20]}」"''' B_NEW = ''' self._fullscreen_window(builder, title=text[:40]) return f"已全屏显示「{text[:20]}」"''' def main() -> int: ok = True text = FEATURES.read_text(encoding="utf-8") for old, new, tag in ((F_OLD, F_NEW, "loop_play 不再碰 Actions 内部"), (W_OLD, W_NEW, "_fullscreen_window 加 title 参数"), (W2_OLD, W2_NEW, "全屏窗口设标题"), (B_OLD, B_NEW, "全屏大字用文字当标题")): if old not in text: print(f" [失败] {tag} —— 锚点没找到") ok = False continue text = text.replace(old, new, 1) print(f" {tag}") FEATURES.write_text(text, encoding="utf-8") text = ACTIONS.read_text(encoding="utf-8") if A_OLD not in text: print(" [失败] play_audio 锚点没找到") ok = False else: text = text.replace(A_OLD, A_NEW, 1) ACTIONS.write_text(text, encoding="utf-8") print(" Actions: 加了 set_loop / _loop_watch(真循环)") # _loop / _loop_thread / _audio_path 初始化 text = ACTIONS.read_text(encoding="utf-8") if "self._loop =" not in text.split("def set_loop")[0]: old = " self._audio_alias = \"\"" if old in text: text = text.replace( old, " self._audio_alias = \"\"\n" " self._audio_path = \"\"\n" " self._loop = False\n" " self._loop_thread = None", 1) ACTIONS.write_text(text, encoding="utf-8") print(" Actions: 加了 _loop / _loop_thread / _audio_path 初始化") else: print(" [跳过] 初始化锚点没找到(用 getattr 兜底也可以,但最好补上)") else: print(" 初始化已存在") import ast for label, path in (("features.py", FEATURES), ("actions.py", ACTIONS)): try: ast.parse(path.read_text(encoding="utf-8")) print(f" {label}: 语法 OK") except SyntaxError as exc: print(f" {label}: 语法错误 {exc}") ok = False return 0 if ok else 1 if __name__ == "__main__": sys.exit(main())