From 5cb42a47e79d6b80da8b0f1ddecbd90358904605 Mon Sep 17 00:00:00 2001 From: Masahiro Hiraki Date: Mon, 1 Jun 2026 08:52:30 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20OBS=E7=AE=A1=E7=90=86=E8=80=85=E6=A8=A9?= =?UTF-8?q?=E9=99=90=E8=B5=B7=E5=8B=95=E3=81=AE=E8=A8=AD=E5=AE=9AUI?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E3=83=BB=E9=8C=B2=E7=94=BB=E5=81=9C=E6=AD=A2?= =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=A0=E3=83=A9=E3=82=B0=E5=89=8A=E6=B8=9B?= =?UTF-8?q?=EF=BC=881=E7=A7=92=E3=83=9D=E3=83=BC=E3=83=AA=E3=83=B3?= =?UTF-8?q?=E3=82=B0=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 開発版 PR #49 を公開版へ反映。 1. OBS 管理者権限起動(launch_as_admin) - OBSConfig に launch_as_admin フィールド追加(デフォルト true) - OBS設定画面に「OBSを管理者権限で起動する」チェックボックスを追加 - prepare_obs_on_startup でハードコード→モデル値に変更 2. 録画停止タイムラグの削減 - _watch_process ポーリング 5000ms → 1000ms - 最悪ケースのタイムラグ: 約10秒 → 約2秒 Co-Authored-By: Claude Opus 4.8 --- configs/example.json | 1 + playcue/config/loader.py | 1 + playcue/config/serializer.py | 1 + playcue/models.py | 1 + playcue/ui/app.py | 5 +++-- playcue/ui/i18n.py | 4 ++++ playcue/ui/obs_settings.py | 17 +++++++++++++++++ 7 files changed, 28 insertions(+), 2 deletions(-) diff --git a/configs/example.json b/configs/example.json index 38fdbd9..d04b633 100644 --- a/configs/example.json +++ b/configs/example.json @@ -9,6 +9,7 @@ "obs": { "enabled": false, "auto_launch": false, + "launch_as_admin": true, "exe_path": "C:/Path/To/OBS/obs64.exe", "working_dir": "C:/Path/To/OBS", "args": "--minimize-to-tray", diff --git a/playcue/config/loader.py b/playcue/config/loader.py index 02952bd..fd5e57f 100644 --- a/playcue/config/loader.py +++ b/playcue/config/loader.py @@ -163,6 +163,7 @@ def _parse_obs(value: object) -> OBSConfig: return OBSConfig( enabled=bool(value.get("enabled", False)), auto_launch=bool(value.get("auto_launch", False)), + launch_as_admin=bool(value.get("launch_as_admin", True)), exe_path=str(value.get("exe_path", "")).strip(), working_dir=str(value.get("working_dir", "")).strip(), args=str(value.get("args", "")).strip(), diff --git a/playcue/config/serializer.py b/playcue/config/serializer.py index 3ec4270..a295f23 100644 --- a/playcue/config/serializer.py +++ b/playcue/config/serializer.py @@ -7,6 +7,7 @@ def obs_config_to_dict(config: OBSConfig) -> dict[str, object]: return { "enabled": config.enabled, "auto_launch": config.auto_launch, + "launch_as_admin": config.launch_as_admin, "exe_path": config.exe_path, "working_dir": config.working_dir, "args": config.args, diff --git a/playcue/models.py b/playcue/models.py index f14ee00..2059ee8 100644 --- a/playcue/models.py +++ b/playcue/models.py @@ -35,6 +35,7 @@ class LoginBonusConfig: class OBSConfig: enabled: bool = False auto_launch: bool = False + launch_as_admin: bool = True exe_path: str = "" working_dir: str = "" args: str = "" diff --git a/playcue/ui/app.py b/playcue/ui/app.py index a48ad6c..7486a8d 100644 --- a/playcue/ui/app.py +++ b/playcue/ui/app.py @@ -614,6 +614,7 @@ def update_obs_settings(self, obs_config: OBSConfig) -> None: "websocket_port": obs_config.websocket_port, "websocket_password": obs_config.websocket_password, "auto_launch": obs_config.auto_launch, + "launch_as_admin": obs_config.launch_as_admin, "auto_start_recording_on_game_launch": obs_config.auto_start_recording_on_game_launch, "auto_stop_recording_on_game_exit": obs_config.auto_stop_recording_on_game_exit, } @@ -650,7 +651,7 @@ def prepare_obs_on_startup(self) -> None: def worker() -> None: try: self.obs_controller.prepare( - launch_as_admin=True, + launch_as_admin=self.obs_controller.config.launch_as_admin, show_window=True, show_errors=False, connect_timeout_seconds=5, @@ -795,7 +796,7 @@ def _watch_process(self) -> None: return watcher.tick() if self.watcher is watcher and not watcher.stopped: - self.root.after(5000, self._watch_process) + self.root.after(1000, self._watch_process) def _refresh_links(self) -> None: if self.link_body is None: diff --git a/playcue/ui/i18n.py b/playcue/ui/i18n.py index fea263e..2798b69 100644 --- a/playcue/ui/i18n.py +++ b/playcue/ui/i18n.py @@ -67,6 +67,8 @@ "obs_enable_desc": "OBS録画機能を使う場合だけ有効にします。", "obs_auto_launch": "OBSを自動起動する", "obs_auto_launch_desc": "ゲーム起動前に OBS を自動起動します。", + "obs_launch_as_admin": "OBSを管理者権限で起動する", + "obs_launch_as_admin_desc": "OBS を管理者権限で起動します。ゲームキャプチャに管理者権限が必要な場合は有効にしてください。", "obs_auto_start_recording": "ゲーム開始時に録画を自動開始する", "obs_auto_start_recording_desc": "ゲーム本体プロセスを検知したら録画を開始します。", "obs_auto_stop_recording": "ゲーム終了時に録画を自動停止する", @@ -220,6 +222,8 @@ "obs_enable_desc": "Enable this only when using OBS recording.", "obs_auto_launch": "Launch OBS automatically", "obs_auto_launch_desc": "Automatically launch OBS before recording.", + "obs_launch_as_admin": "Launch OBS as administrator", + "obs_launch_as_admin_desc": "Launch OBS with administrator privileges. Enable this if game capture requires admin rights.", "obs_auto_start_recording": "Start recording when game starts", "obs_auto_start_recording_desc": "Start recording when the game process is detected.", "obs_auto_stop_recording": "Stop recording when game exits", diff --git a/playcue/ui/obs_settings.py b/playcue/ui/obs_settings.py index dbc4229..70bdeb8 100644 --- a/playcue/ui/obs_settings.py +++ b/playcue/ui/obs_settings.py @@ -69,6 +69,7 @@ def __init__(self, parent: Tk, config: OBSConfig, on_saved): self.websocket_port_var = tk.StringVar(value=str(config.websocket_port)) self.websocket_password_var = tk.StringVar(value=config.websocket_password) self.auto_launch_var = tk.BooleanVar(value=config.auto_launch) + self.launch_as_admin_var = tk.BooleanVar(value=config.launch_as_admin) self.auto_start_recording_var = tk.BooleanVar(value=config.auto_start_recording_on_game_launch) self.auto_stop_recording_var = tk.BooleanVar(value=config.auto_stop_recording_on_game_exit) self._dependent_widgets: list[tk.Widget] = [] @@ -135,6 +136,21 @@ def _build_ui(self) -> None: ) auto_launch_desc.pack(anchor=tk.W, padx=20, pady=(0, 4)) + launch_as_admin_cb = _make_checkbutton( + automation_frame, + text=tr("obs_launch_as_admin"), + variable=self.launch_as_admin_var, + ) + launch_as_admin_cb.pack(anchor=tk.W, padx=6, pady=(0, 0)) + launch_as_admin_desc = ttk.Label( + automation_frame, + text=tr("obs_launch_as_admin_desc"), + foreground="#9aa9c4", + wraplength=480, + ) + launch_as_admin_desc.pack(anchor=tk.W, padx=20, pady=(0, 4)) + self._dependent_widgets.append(launch_as_admin_cb) + auto_start_cb = _make_checkbutton( automation_frame, text=tr("obs_auto_start_recording"), @@ -222,6 +238,7 @@ def save(self) -> None: websocket_port=port, websocket_password=self.websocket_password_var.get(), auto_launch=self.auto_launch_var.get(), + launch_as_admin=self.launch_as_admin_var.get(), auto_start_recording_on_game_launch=self.auto_start_recording_var.get(), auto_stop_recording_on_game_exit=self.auto_stop_recording_var.get(), )