]> skyeroc.xyz Git - obs-ctl/commitdiff
Add settings for theme and update interval
authorsbkelley <sb24kelley@gmail.com>
Mon, 8 Dec 2025 00:43:43 +0000 (19:43 -0500)
committersbkelley <sb24kelley@gmail.com>
Mon, 8 Dec 2025 00:43:43 +0000 (19:43 -0500)
src/obs_ctl/app.py
src/obs_ctl/const.py
src/obs_ctl/interface/molecule/settings_block/settings_block.py
src/obs_ctl/interface/molecule/settings_block/settings_block.pyi
src/obs_ctl/interface/obs/obs.py

index 832a26bfc6fdd88f3fd392c2db224dffbb88d9ee..3d9e0ed7984698cfc48fbfe01d0805c6bbfb2a9e 100644 (file)
@@ -11,7 +11,7 @@ from textual.widgets import Footer, Header
 
 # need to import log to initalize logging
 from . import data, const, log # type: ignore
-from .interface import RecordControls, StatsDisplay, SettingsBlock, obs, OBSWebSocketPane, OBSSettingsPane
+from .interface import RecordControls, StatsDisplay, SettingsBlock, obs, OBSWebSocketPane, OBSSettingsPane, OBSCTLPane
 
 logger = getLogger(__name__)
 
@@ -28,7 +28,7 @@ class OBSCtlApp(App): # type: ignore
     def compose(self):
         yield Header()
         yield Footer()
-        yield obs.API(1, ws_host=const.HOST, ws_port=const.PORT, ws_password=const.PASSWORD, ws_timeout=const.TIMEOUT, id="api")
+        yield obs.API(const.UPDATE_INTERVAL, ws_host=const.HOST, ws_port=const.PORT, ws_password=const.PASSWORD, ws_timeout=const.TIMEOUT, id="api")
         logger.debug("Composing OBSCtlApp")
         with ScrollableContainer(classes="scrollbox"):
             with VerticalGroup(classes="content"):
@@ -40,13 +40,14 @@ class OBSCtlApp(App): # type: ignore
 
 
     def on_mount(self, message: events.Mount):
+        self.theme = const.THEME
         obsws_pane = self.get_websocket_pane()
         api = self.get_api()
         obsws_pane.host = api.ws_host
         obsws_pane.port = api.ws_port
         obsws_pane.password = api.ws_password
         obsws_pane.timeout = api.ws_timeout
-        # self.get_api().on_record_state_changed(namedtuple("test", ("output_state"))(output_state="OBS_WEBSOCKET_OUTPUT_STARTED"))
+        # TODO: Update obsctl settings (like UPDATE_INTERVAL) also
 
 
     @on(obs.API.Report, "#api")
@@ -172,6 +173,20 @@ class OBSCtlApp(App): # type: ignore
         self.get_api().set_record_path(message.value)
 
 
+    @on(OBSCTLPane.ThemeSubmitted, "#obs_ctl_pane")
+    def on_settings_block_obsctl_theme_changed(self, message: OBSCTLPane.ThemeSubmitted):
+        self.theme = message.value
+
+
+    @on(OBSCTLPane.UpdateIntervalSubmitted, "#obs_ctl_pane")
+    def on_settings_block_obsctl_update_interval_changed(self, message:OBSCTLPane.ThemeSubmitted):
+        self.get_api().interval = message.value
+
+
+    def watch_theme(self, value):
+        self.get_obs_ctl_pane().theme = value
+
+
     def update_monitors(self, obs_stats: obs.OBSStats):
         self.get_settings_pane().record_path = obs_stats.record_directory
         self.get_stats_display().update_text_readouts(obs_stats)
@@ -192,5 +207,9 @@ class OBSCtlApp(App): # type: ignore
         return typing.cast(OBSSettingsPane, self.query_exactly_one("#obs_settings_pane"))
 
 
+    def get_obs_ctl_pane(self) -> OBSCTLPane:
+        return self.query_exactly_one("#obs_ctl_pane") # type: ignore
+
+
     def get_stats_display(self) -> StatsDisplay:
         return typing.cast(StatsDisplay, self.query_exactly_one("#stats_display"))
\ No newline at end of file
index 67b860664749f49a8536603e16f224c53a3d4969..c32ad6148e5238de0e7533bd68e35fce57a3028d 100644 (file)
@@ -1,18 +1,36 @@
 from platformdirs import PlatformDirs
 from configparser import ConfigParser
+# App Info
 APPNAME = "obs-ctl"
 APPAUTHOR = "skyebee"
 VERSION = "0.0.1"
-
+# Useful classes
 USERDIRS = PlatformDirs(APPNAME, APPAUTHOR, ensure_exists=True)
-
 CONFIG = ConfigParser()
-
+# Config-related
 POSSIBLE_CONFIG: list[str] = [USERDIRS.user_config_dir]
 CURRENT_CONFIG = CONFIG.read(POSSIBLE_CONFIG)
-
-
+# OBS WebSocket
 HOST = "localhost"
 PORT = 4455
 PASSWORD = ""
-TIMEOUT = 1.0
\ No newline at end of file
+TIMEOUT = 1.0
+# obs-ctl
+UPDATE_INTERVAL = 1.0
+THEME = "monokai"
+
+# internal
+AVAILABLE_THEMES = [
+    'textual-dark',
+    'textual-light',
+    'nord',
+    'gruvbox',
+    'catppuccin-mocha',
+    'textual-ansi',
+    'dracula',
+    'tokyo-night',
+    'monokai',
+    'flexoki',
+    'catppuccin-latte',
+    'solarized-light'
+]
\ No newline at end of file
index 93c20110e64c8dd2f9f2d4252cb9730e72c8051a..523fe3b143eabf0dbf0c273e1ba4bbcfcb7413b1 100644 (file)
@@ -1,7 +1,8 @@
-from textual.widgets import TabbedContent
+from textual.widgets import TabbedContent, Select
 from textual.containers import Container
 
 from . import pane
+from .... import const
 
 OBSSettingsPane = pane.make_pane(
     "OBSSettingsPane",
@@ -13,22 +14,31 @@ OBSSettingsPane = pane.make_pane(
 
 OBSWebSocketPane = pane.make_pane(
     "OBSWebSocketPane",
-    pane.make_pane_widget("host", pane.SettingsWidget.STRING, "", compact=True),
-    pane.make_pane_widget("port", pane.SettingsWidget.INT, 0, compact=True),
-    pane.make_pane_widget("password", pane.SettingsWidget.STRING, "", compact=True),
-    pane.make_pane_widget("timeout", pane.SettingsWidget.FLOAT, 0.0, compact=True),
+    pane.make_pane_widget("host", pane.SettingsWidget.STRING, const.HOST, compact=True),
+    pane.make_pane_widget("port", pane.SettingsWidget.INT, const.PORT, compact=True),
+    pane.make_pane_widget("password", pane.SettingsWidget.STRING, const.PASSWORD, compact=True),
+    pane.make_pane_widget("timeout", pane.SettingsWidget.FLOAT, const.TIMEOUT, compact=True),
 )
 
 OBSCTLPane = pane.make_pane(
     "OBSCTLPane",
-    names_list=["nothing"],
-    settings_type_list=[pane.SettingsWidget.STRING],
-    defaults_list=["zilch"]
+    pane.make_pane_widget(
+        "theme",
+        pane.SettingsWidget.LIST,
+        const.THEME,
+        zip(const.AVAILABLE_THEMES, const.AVAILABLE_THEMES),
+        allow_blank=False,
+        compact=True),
+    pane.make_pane_widget(
+        "update_interval",
+        pane.SettingsWidget.FLOAT,
+        const.UPDATE_INTERVAL,
+        compact=True,
+    )
 )
-
 class SettingsBlock(Container):
     def compose(self):
         with TabbedContent(classes="settings_block--tabbed-content"):
             yield OBSSettingsPane("OBS Settings", id="obs_settings_pane")
             yield OBSWebSocketPane("OBS WebSocket", id="obs_websocket_pane")
-            yield OBSCTLPane("obs-ctl Settings", id="obs_ctl_pane")
+            yield OBSCTLPane("obs-ctl Settings", id="obs_ctl_pane")
index 6bd5a0b852e11478a8c81eea2a307eee462c22df..d85571cf7917c9c11c9521bf4c37f834055d23c4 100644 (file)
@@ -20,7 +20,6 @@ class OBSSettingsPane(PaneBaseSubclass):
     class RecordPathSubmitted(pane.SettingsMSGBase): ...
     def watch_record_path(self: Self, value: str) -> None: ...
     def on_record_path_submitted(self: Self, event: pane.SettingsMSGBase) -> None: ...
-    def compose(self: Self) -> ComposeResult: ...
 
 class OBSWebSocketPane(PaneBaseSubclass):
     host: ClassVar[reactive[str]]
@@ -39,9 +38,16 @@ class OBSWebSocketPane(PaneBaseSubclass):
     def on_port_submitted(self: Self, event: pane.SettingsMSGBase) -> None: ...
     def on_password_submitted(self: Self, event: pane.SettingsMSGBase) -> None: ...
     def on_timeout_submitted(self: Self, event: pane.SettingsMSGBase) -> None: ...
-    def compose(self: Self) -> ComposeResult: ...
 
-class OBSCTLPane(PaneBaseSubclass): ...
+class OBSCTLPane(PaneBaseSubclass):
+    theme: ClassVar[reactive[str]]
+    class ThemeSubmitted(pane.SettingsMSGBase): ...
+    def watch_theme(self: Self, value: str) -> None: ...
+    def on_theme_submitted(self: Self, event: pane.SettingsMSGBase) -> None: ...
+    update_interval: ClassVar[reactive[float]]
+    class UpdateIntervalSubmitted(pane.SettingsMSGBase): ...
+    def watch_update_interval(self: Self, value: str) -> None: ...
+    def on_update_interval_submitted(self: Self, event: pane.SettingsMSGBase) -> None: ...
 
 class SettingsBlock(Container):
     def compose(self) -> ComposeResult: ...
index 6c386604e20502981ffbb2986060adbe88a2edb2..c217c0752eb89952e4887c9eb374fed97a631748 100644 (file)
@@ -152,7 +152,7 @@ class API(Static):
     _last_stream_state: reactive["OutputStates"] = reactive(OutputStates.STOPPED)
     _last_record_state: reactive["OutputStates"] = reactive(OutputStates.STOPPED)
     _trying_request: bool = False
-    _timer: Timer | None = None
+    _timer: Timer
 
     interval: reactive[float] = reactive(1.0)
     ws_host: reactive[str] = reactive("localhost")
@@ -232,7 +232,9 @@ class API(Static):
  
  
     def watch_interval(self, value: float) -> None:
-        self._reset_timer(value)
+        self._timer.stop()
+        self._reset_timer(float(value))
+        pass
 
 
     def watch_ws_host(self, value: str) -> None: