From: sbkelley Date: Mon, 8 Dec 2025 00:43:43 +0000 (-0500) Subject: Add settings for theme and update interval X-Git-Url: https://skyeroc.xyz/gitweb/?a=commitdiff_plain;h=c2fe26c45ea8d5f4353f3e101d5b78ded43b9097;p=obs-ctl Add settings for theme and update interval --- diff --git a/src/obs_ctl/app.py b/src/obs_ctl/app.py index 832a26b..3d9e0ed 100644 --- a/src/obs_ctl/app.py +++ b/src/obs_ctl/app.py @@ -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 diff --git a/src/obs_ctl/const.py b/src/obs_ctl/const.py index 67b8606..c32ad61 100644 --- a/src/obs_ctl/const.py +++ b/src/obs_ctl/const.py @@ -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 diff --git a/src/obs_ctl/interface/molecule/settings_block/settings_block.py b/src/obs_ctl/interface/molecule/settings_block/settings_block.py index 93c2011..523fe3b 100644 --- a/src/obs_ctl/interface/molecule/settings_block/settings_block.py +++ b/src/obs_ctl/interface/molecule/settings_block/settings_block.py @@ -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") diff --git a/src/obs_ctl/interface/molecule/settings_block/settings_block.pyi b/src/obs_ctl/interface/molecule/settings_block/settings_block.pyi index 6bd5a0b..d85571c 100644 --- a/src/obs_ctl/interface/molecule/settings_block/settings_block.pyi +++ b/src/obs_ctl/interface/molecule/settings_block/settings_block.pyi @@ -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: ... diff --git a/src/obs_ctl/interface/obs/obs.py b/src/obs_ctl/interface/obs/obs.py index 6c38660..c217c07 100644 --- a/src/obs_ctl/interface/obs/obs.py +++ b/src/obs_ctl/interface/obs/obs.py @@ -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: