From d9949a859a8bd59f0f2293263232abb9e58e4184 Mon Sep 17 00:00:00 2001 From: Caesar Date: Sun, 19 Oct 2025 19:00:37 +0200 Subject: [PATCH 1/5] feat: enabled ipv6 support and non localhost adresses --- backend/OBSController.py | 58 +++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/backend/OBSController.py b/backend/OBSController.py index 73b5d18..8e95c32 100644 --- a/backend/OBSController.py +++ b/backend/OBSController.py @@ -12,26 +12,58 @@ def __init__(self): pass def validate_ip(self, host: str): - if host in ("localhost", "127.0.0.1"): - return True + """ + Validate host address (IPv4, IPv6, or hostname). + + Returns True if the host is valid, False otherwise. + """ + if not host or not host.strip(): + return False - # We're explicitly disallowing non-localhost DNS entries here. - # Continuing this pattern for now, but this is probably the wrong thing - # to do long-term. + host = host.strip() + # Try to parse as IP address (IPv4 or IPv6) try: - addr = ipaddress.ip_address(host) - - # And we're disallowing IPv6 entries here, for compatibility with - # previous implementations. Again, probably the wrong thing - # long-term, but implementing this way to mitigate risk while we're - # in a bad-push state. - if not addr.version == ipaddress.IPv4Address.version: - raise ValueError() + ipaddress.ip_address(host) return True except ValueError: + pass + + # Try to validate as hostname/DNS entry + # Valid hostname: alphanumeric, hyphens, dots, max 253 chars + # Each label (between dots) max 63 chars, can't start/end with hyphen + if len(host) > 253: + return False + + # Allow localhost explicitly + if host.lower() == "localhost": + return True + + # Split into labels and validate each + labels = host.split('.') + if not labels: return False + # Pattern for valid hostname labels + for label in labels: + if not label or len(label) > 63: + return False + # Must start and end with alphanumeric + if not (label[0].isalnum() and label[-1].isalnum()): + return False + # Labels can't be all numeric (would be confused with IP) + if label.isdigit(): + # If all labels are numeric, it looks like an IP address + # and should have been caught by ipaddress.ip_address() + if all(l.isdigit() for l in labels): + return False + # Middle characters can be alphanumeric or hyphen + for char in label: + if not (char.isalnum() or char == '-'): + return False + + return True + def on_connect(self, obs): self.connected = True From d84226ccc901bdba3d6088e71184ad393eaa94ae Mon Sep 17 00:00:00 2001 From: Caesar Date: Sun, 19 Oct 2025 19:13:08 +0200 Subject: [PATCH 2/5] fix: properly handling ipv6 --- backend/OBSController.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/backend/OBSController.py b/backend/OBSController.py index 8e95c32..81cab00 100644 --- a/backend/OBSController.py +++ b/backend/OBSController.py @@ -22,6 +22,10 @@ def validate_ip(self, host: str): host = host.strip() + # Handle bracket-wrapped IPv6 addresses [::1] + if host.startswith('[') and host.endswith(']'): + host = host[1:-1] + # Try to parse as IP address (IPv4 or IPv6) try: ipaddress.ip_address(host) @@ -90,18 +94,32 @@ def connect_to(self, host=None, port=None, timeout=1, legacy=False, **kwargs): self.event_obs.disconnect() return False + # For IPv6 addresses, wrap in brackets if not already wrapped + # This is required for WebSocket URL construction (ws://[::1]:port) + connection_host = host + try: + addr = ipaddress.ip_address(host) + if isinstance(addr, ipaddress.IPv6Address): + # Only wrap if not already wrapped + if not (host.startswith('[') and host.endswith(']')): + connection_host = f"[{host}]" + log.debug(f"Wrapped IPv6 address: {host} -> {connection_host}") + except ValueError: + # Not an IP address, use as-is (hostname) + pass + try: log.debug(f"Trying to connect to obs with legacy: {legacy}") - super().__init__(host=host, port=port, timeout=timeout, legacy=legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) - self.event_obs = obsws(host=host, port=port, timeout=timeout, legacy=legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) + super().__init__(host=connection_host, port=port, timeout=timeout, legacy=legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) + self.event_obs = obsws(host=connection_host, port=port, timeout=timeout, legacy=legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) self.connect() log.info("Successfully connected to OBS") return True except (obswebsocket.exceptions.ConnectionFailure, ValueError) as e: try: log.error(f"Failed to connect to OBS with legacy: {legacy}, trying with legacy: {not legacy}") - super().__init__(host=host, port=port, timeout=timeout, legacy=not legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) - self.event_obs = obsws(host=host, port=port, timeout=timeout, legacy=not legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) + super().__init__(host=connection_host, port=port, timeout=timeout, legacy=not legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) + self.event_obs = obsws(host=connection_host, port=port, timeout=timeout, legacy=not legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) self.connect() log.info("Successfully connected to OBS") From e70512b465899578dd782c264053760b7a76e236 Mon Sep 17 00:00:00 2001 From: Caesar Date: Sun, 19 Oct 2025 20:09:12 +0200 Subject: [PATCH 3/5] chore: split validate_ip into two, to reduce complexity --- backend/OBSController.py | 51 ++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/backend/OBSController.py b/backend/OBSController.py index 81cab00..2dea994 100644 --- a/backend/OBSController.py +++ b/backend/OBSController.py @@ -11,29 +11,15 @@ def __init__(self): self.event_obs: obsws = None # All events are connected to this to avoid crash if a request is made in an event pass - def validate_ip(self, host: str): - """ - Validate host address (IPv4, IPv6, or hostname). - - Returns True if the host is valid, False otherwise. + def validate_dns(self, host: str) -> bool: """ - if not host or not host.strip(): - return False - - host = host.strip() + Validate hostname/DNS entry. - # Handle bracket-wrapped IPv6 addresses [::1] - if host.startswith('[') and host.endswith(']'): - host = host[1:-1] + Valid hostname: alphanumeric, hyphens, dots, max 253 chars. + Each label (between dots) max 63 chars, can't start/end with hyphen. - # Try to parse as IP address (IPv4 or IPv6) - try: - ipaddress.ip_address(host) - return True - except ValueError: - pass - - # Try to validate as hostname/DNS entry + Returns True if the hostname is valid, False otherwise. + """ # Valid hostname: alphanumeric, hyphens, dots, max 253 chars # Each label (between dots) max 63 chars, can't start/end with hyphen if len(host) > 253: @@ -68,6 +54,31 @@ def validate_ip(self, host: str): return True + def validate_ip(self, host: str): + """ + Validate host address (IPv4, IPv6, or hostname). + + Returns True if the host is valid, False otherwise. + """ + if not host or not host.strip(): + return False + + host = host.strip() + + # Handle bracket-wrapped IPv6 addresses [::1] + if host.startswith('[') and host.endswith(']'): + host = host[1:-1] + + # Try to parse as IP address (IPv4 or IPv6) + try: + ipaddress.ip_address(host) + return True + except ValueError: + pass + + # Try to validate as hostname/DNS entry + return self.validate_dns(host) + def on_connect(self, obs): self.connected = True From bb988f5dc562a0cc33cfc72c474797e6ac0afc66 Mon Sep 17 00:00:00 2001 From: Caesar Date: Sun, 19 Oct 2025 20:11:09 +0200 Subject: [PATCH 4/5] chore: linting --- OBSActionBase.py | 31 +- __install__.py | 4 +- actions/Filter/FilterBase.py | 43 +- actions/InputDial/InputDial.py | 102 +++-- actions/InputMute/InputMuteBase.py | 33 +- actions/RecPlayPause/RecPlayPause.py | 11 +- actions/SaveReplayBuffer/SaveReplayBuffer.py | 16 +- actions/SceneItem/SceneItem.py | 45 ++- actions/SwitchScene/SwitchScene.py | 19 +- .../SwitchSceneCollection.py | 36 +- actions/ToggleRecord/ToggleRecord.py | 26 +- .../ToggleReplayBuffer/ToggleReplayBuffer.py | 38 +- actions/ToggleStream/ToggleStream.py | 42 +- actions/ToggleStudioMode/ToggleStudioMode.py | 38 +- .../ToggleVirtualCamera.py | 42 +- .../TriggerTransition/TriggerTransition.py | 13 +- actions/mixins/MixinBase.py | 4 +- actions/mixins/SetMixin.py | 11 +- backend/OBSController.py | 368 ++++++++++++++---- backend/backend.py | 51 ++- 20 files changed, 725 insertions(+), 248 deletions(-) diff --git a/OBSActionBase.py b/OBSActionBase.py index a2de89a..80faa06 100644 --- a/OBSActionBase.py +++ b/OBSActionBase.py @@ -21,17 +21,22 @@ def __init__(self, *args, **kwargs): self.has_configuration = True self.status_label = Gtk.Label( - label=self.plugin_base.lm.get("actions.base.status.no-connection"), css_classes=["bold", "red"] + label=self.plugin_base.lm.get("actions.base.status.no-connection"), + css_classes=["bold", "red"], ) if not self.plugin_base.backend.get_connected(): self.reconnect_obs() def get_config_rows(self) -> list: - self.ip_entry = Adw.EntryRow(title=self.plugin_base.lm.get("actions.base.ip.label")) + self.ip_entry = Adw.EntryRow( + title=self.plugin_base.lm.get("actions.base.ip.label") + ) self.port_spinner = Adw.SpinRow.new_with_range(0, 65535, 1) self.port_spinner.set_title(self.plugin_base.lm.get("actions.base.port.label")) - self.password_entry = Adw.PasswordEntryRow(title=self.plugin_base.lm.get("actions.base.password.label")) + self.password_entry = Adw.PasswordEntryRow( + title=self.plugin_base.lm.get("actions.base.password.label") + ) self.load_config_defaults() @@ -64,7 +69,9 @@ def on_change_ip(self, entry, *args): self.reconnect_obs() def update_ip_warning_status(self): - valid = self.plugin_base.backend.OBSController.validate_ip(self.ip_entry.get_text().strip()) + valid = self.plugin_base.backend.OBSController.validate_ip( + self.ip_entry.get_text().strip() + ) if valid: self.ip_entry.remove_css_class("error") else: @@ -85,7 +92,9 @@ def on_change_password(self, entry, *args): self.reconnect_obs() def reconnect_obs(self): - threading.Thread(target=self._reconnect_obs, daemon=True, name="reconnect_obs").start() + threading.Thread( + target=self._reconnect_obs, daemon=True, name="reconnect_obs" + ).start() def _reconnect_obs(self): try: @@ -103,17 +112,23 @@ def _reconnect_obs(self): self.update_status_label() def update_status_label(self) -> None: - threading.Thread(target=self._update_status_label, daemon=True, name="update_status_label").start() + threading.Thread( + target=self._update_status_label, daemon=True, name="update_status_label" + ).start() def _update_status_label(self): if self.plugin_base.backend.get_connected(): print("connected - label") - self.status_label.set_label(self.plugin_base.lm.get("actions.base.status.connected")) + self.status_label.set_label( + self.plugin_base.lm.get("actions.base.status.connected") + ) self.status_label.remove_css_class("red") self.status_label.add_css_class("green") else: print("not connected - label") - self.status_label.set_label(self.plugin_base.lm.get("actions.base.status.no-connection")) + self.status_label.set_label( + self.plugin_base.lm.get("actions.base.status.no-connection") + ) self.status_label.remove_css_class("green") self.status_label.add_css_class("red") diff --git a/__install__.py b/__install__.py index 5a1a84f..4c7d678 100644 --- a/__install__.py +++ b/__install__.py @@ -2,4 +2,6 @@ from os.path import join, abspath, dirname toplevel = dirname(abspath(__file__)) -create_venv(join(toplevel, "backend", ".venv"), join(toplevel, "backend", "requirements.txt")) +create_venv( + join(toplevel, "backend", ".venv"), join(toplevel, "backend", "requirements.txt") +) diff --git a/actions/Filter/FilterBase.py b/actions/Filter/FilterBase.py index 9933c4b..b597a06 100644 --- a/actions/Filter/FilterBase.py +++ b/actions/Filter/FilterBase.py @@ -10,6 +10,7 @@ # Import gtk modules import gi + gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Gtk, Adw @@ -28,7 +29,11 @@ def on_ready(self): self.reconnect_obs() # Show current scene filter status - threading.Thread(target=self.show_current_filter_status, daemon=True, name="show_current_filter_status").start() + threading.Thread( + target=self.show_current_filter_status, + daemon=True, + name="show_current_filter_status", + ).start() def show_current_filter_status(self): if not self.plugin_base.get_connected(): @@ -40,7 +45,9 @@ def show_current_filter_status(self): self.show_error() return - status = self.plugin_base.backend.get_source_filter(self.get_settings().get("scene"), self.get_settings().get("filter")) + status = self.plugin_base.backend.get_source_filter( + self.get_settings().get("scene"), self.get_settings().get("filter") + ) if status is None: self.current_state = State.UNKNOWN self.show_error() @@ -67,16 +74,26 @@ def show_for_state(self, state: State): elif state == State.ENABLED: image = "scene_item_enabled.png" - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", image), size=0.75) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", image), size=0.75 + ) def get_config_rows(self) -> list: super_rows = super().get_config_rows() self.scene_model = Gtk.StringList() - self.scene_row = Adw.ComboRow(model=self.scene_model, title=self.plugin_base.lm.get("actions.switch.scene-row.label")) + self.scene_row = Adw.ComboRow( + model=self.scene_model, + title=self.plugin_base.lm.get("actions.switch.scene-row.label"), + ) self.filter_model = Gtk.StringList() - self.filter_row = Adw.ComboRow(model=self.filter_model, title=self.plugin_base.lm.get("actions.toggle-scene-filter-enabled-row.label")) + self.filter_row = Adw.ComboRow( + model=self.filter_model, + title=self.plugin_base.lm.get( + "actions.toggle-scene-filter-enabled-row.label" + ), + ) self.connect_signals() @@ -178,20 +195,28 @@ def on_key_down(self): if not self.plugin_base.get_connected(): self.current_state = State.UNKNOWN self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return scene_name = self.get_settings().get("scene") filter_name = self.get_settings().get("filter") if scene_name in [None, ""]: - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if filter_name in [None, ""]: - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return next_state = bool(self.next_state().value) - self.plugin_base.backend.set_source_filter_enabled(scene_name, filter_name, next_state) + self.plugin_base.backend.set_source_filter_enabled( + scene_name, filter_name, next_state + ) self.on_tick() def on_tick(self): diff --git a/actions/InputDial/InputDial.py b/actions/InputDial/InputDial.py index 82ae407..e98db99 100644 --- a/actions/InputDial/InputDial.py +++ b/actions/InputDial/InputDial.py @@ -11,10 +11,12 @@ # Import gtk modules import gi + gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Gtk, Adw + class InputDial(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -28,44 +30,62 @@ def on_ready(self): if self.plugin_base.backend is not None: if not self.plugin_base.get_connected(): self.reconnect_obs() - + # Show current input volume self.muted = None self.volume = None - threading.Thread(target=self.show_current_input_volume, daemon=True, name="show_current_input_volume").start() - + threading.Thread( + target=self.show_current_input_volume, + daemon=True, + name="show_current_input_volume", + ).start() + def show_current_input_volume(self): if self.plugin_base.backend is None: self.current_state = None self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if not self.plugin_base.backend.get_connected(): self.current_state = None self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if not self.get_settings().get("input"): self.current_state = None self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return - + # update muted - status = self.plugin_base.backend.get_input_muted(self.get_settings().get("input")) + status = self.plugin_base.backend.get_input_muted( + self.get_settings().get("input") + ) if status is None: self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return self.muted = status["muted"] # update volume - status = self.plugin_base.backend.get_input_volume(self.get_settings().get("input")) + status = self.plugin_base.backend.get_input_volume( + self.get_settings().get("input") + ) if status is None: self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return self.volume = self.db_to_volume(status["volume"]) @@ -75,7 +95,10 @@ def show_current_input_volume(self): if self.last_muted != self.muted: self.last_muted = self.muted - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", image), size=0.9) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", image), + size=0.9, + ) if self.last_volume != self.volume: self.last_volume = self.volume self.set_label(label) @@ -84,7 +107,10 @@ def get_config_rows(self) -> list: super_rows = super().get_config_rows() self.input_model = Gtk.StringList() - self.input_row = Adw.ComboRow(model=self.input_model, title=self.plugin_base.lm.get("actions.input-dial-row.label")) + self.input_row = Adw.ComboRow( + model=self.input_model, + title=self.plugin_base.lm.get("actions.input-dial-row.label"), + ) self.connect_signals() @@ -102,7 +128,7 @@ def disconnect_signals(self): self.input_row.disconnect_by_func(self.on_input_change) except TypeError as e: pass - + def load_input_model(self): self.disconnect_signals() # Clear model @@ -113,7 +139,11 @@ def load_input_model(self): if self.plugin_base.backend.get_connected(): inputs = self.plugin_base.backend.get_inputs() if inputs is None: - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join( + self.plugin_base.PATH, "assets", "error.png" + ) + ) return for input in inputs: self.input_model.append(input) @@ -131,10 +161,10 @@ def load_selected_device(self): self.input_row.set_selected(i) self.connect_signals() return - + self.input_row.set_selected(Gtk.INVALID_LIST_POSITION) self.connect_signals() - + def on_input_change(self, *args): settings = self.get_settings() selected_index = self.input_row.get_selected() @@ -153,46 +183,60 @@ def mute_toggle(self): if self.plugin_base.backend is None: self.current_state = None self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if not self.plugin_base.backend.get_connected(): self.current_state = None self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return input_name = self.get_settings().get("input") if input_name in [None, ""]: - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return self.muted = not self.muted self.plugin_base.backend.set_input_muted(input_name, self.muted) self.on_tick() - + def volume_change(self, diff): if self.plugin_base.backend is None: self.current_state = None self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if not self.plugin_base.backend.get_connected(): self.current_state = None self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return input_name = self.get_settings().get("input") if input_name in [None, ""]: - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return - + self.volume += diff if self.volume < 0: self.volume = 0 if self.volume > 100: self.volume = 100 - self.plugin_base.backend.set_input_volume(input_name, self.volume_to_db(self.volume)) + self.plugin_base.backend.set_input_volume( + input_name, self.volume_to_db(self.volume) + ) self.on_tick() def on_tick(self): @@ -205,17 +249,17 @@ def reconnect_obs(self): self.load_configs() self.muted = None self.volume = None - + def volume_to_db(self, vol): if vol == 0: return -100 if vol > 100: return 0 - return math.log(vol/100)*10/math.log(1.5) + return math.log(vol / 100) * 10 / math.log(1.5) def db_to_volume(self, db): if db < -100: return 0 if db > 0: return 100 - return math.floor(1.5**(db/10) * 100) \ No newline at end of file + return math.floor(1.5 ** (db / 10) * 100) diff --git a/actions/InputMute/InputMuteBase.py b/actions/InputMute/InputMuteBase.py index 3ff1074..f620054 100644 --- a/actions/InputMute/InputMuteBase.py +++ b/actions/InputMute/InputMuteBase.py @@ -29,8 +29,12 @@ def __init__(self, *args, **kwargs): self.image_path_map = { State.UNKNOWN: os.path.join(self.plugin_base.PATH, "assets", "error.png"), - State.ENABLED: os.path.join(self.plugin_base.PATH, "assets", "input_unmuted.png"), - State.DISABLED: os.path.join(self.plugin_base.PATH, "assets", "input_muted.png"), + State.ENABLED: os.path.join( + self.plugin_base.PATH, "assets", "input_unmuted.png" + ), + State.DISABLED: os.path.join( + self.plugin_base.PATH, "assets", "input_muted.png" + ), } @property @@ -52,11 +56,15 @@ def on_ready(self): # Show current input mute status threading.Thread( - target=self.show_current_input_mute_status, daemon=True, name="show_current_input_mute_status" + target=self.show_current_input_mute_status, + daemon=True, + name="show_current_input_mute_status", ).start() def set_media(self, *args, **kwargs): - super().set_media(media_path=self.image_path_map.get(self.current_state), *args, **kwargs) + super().set_media( + media_path=self.image_path_map.get(self.current_state), *args, **kwargs + ) def show_current_input_mute_status(self): if not self.plugin_base.get_connected(): @@ -97,7 +105,8 @@ def get_config_rows(self) -> list: self.input_model = Gtk.StringList() self.input_row = Adw.ComboRow( - model=self.input_model, title=self.plugin_base.lm.get("actions.toggle-input-mute-row.label") + model=self.input_model, + title=self.plugin_base.lm.get("actions.toggle-input-mute-row.label"), ) self.connect_signals() @@ -127,7 +136,11 @@ def load_input_model(self): if self.plugin_base.backend.get_connected(): inputs = self.plugin_base.backend.get_inputs() if inputs is None: - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join( + self.plugin_base.PATH, "assets", "error.png" + ) + ) return for input in inputs: self.input_model.append(input) @@ -166,10 +179,14 @@ def on_key_down(self): except NotConnectedError: self.current_state = State.UNKNOWN self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return except InputNotFoundError: - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return next_state = self.next_state() diff --git a/actions/RecPlayPause/RecPlayPause.py b/actions/RecPlayPause/RecPlayPause.py index 4073a27..42c080f 100644 --- a/actions/RecPlayPause/RecPlayPause.py +++ b/actions/RecPlayPause/RecPlayPause.py @@ -5,6 +5,7 @@ from src.backend.PluginManager.PluginBase import PluginBase import os + class RecPlayPause(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -19,9 +20,13 @@ def on_ready(self): self.reconnect_obs() # Show current rec status - threading.Thread(target=self.show_current_rec_status, daemon=True, name="show_current_rec_status").start() + threading.Thread( + target=self.show_current_rec_status, + daemon=True, + name="show_current_rec_status", + ).start() - def show_current_rec_status(self, new_paused = False): + def show_current_rec_status(self, new_paused=False): if not self.plugin_base.get_connected(): self.show_error() return @@ -65,4 +70,4 @@ def on_key_down(self): self.plugin_base.backend.toggle_record_pause() def on_tick(self): - self.show_current_rec_status() \ No newline at end of file + self.show_current_rec_status() diff --git a/actions/SaveReplayBuffer/SaveReplayBuffer.py b/actions/SaveReplayBuffer/SaveReplayBuffer.py index b4744eb..9c9d8a9 100644 --- a/actions/SaveReplayBuffer/SaveReplayBuffer.py +++ b/actions/SaveReplayBuffer/SaveReplayBuffer.py @@ -6,6 +6,7 @@ from src.backend.PluginManager.PluginBase import PluginBase import os + # from ...OBSActionBase import OBSActionBase import threading from plugins.com_core447_OBSPlugin.OBSActionBase import OBSActionBase @@ -14,6 +15,8 @@ from src.backend.PluginManager.PluginBase import PluginBase import os + + class SaveReplayBuffer(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -21,9 +24,16 @@ def __init__(self, *args, **kwargs): def on_ready(self): # Connect to obs if not connected if self.plugin_base.backend is not None: - if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if ( + not self.plugin_base.get_connected() + ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "replay_buffer_save.png"), size=0.85) + self.set_media( + media_path=os.path.join( + self.plugin_base.PATH, "assets", "replay_buffer_save.png" + ), + size=0.85, + ) def on_key_down(self): if self.plugin_base.backend is None: @@ -32,4 +42,4 @@ def on_key_down(self): if not self.plugin_base.backend.get_connected(): self.show_error() return - self.plugin_base.backend.save_replay_buffer() \ No newline at end of file + self.plugin_base.backend.save_replay_buffer() diff --git a/actions/SceneItem/SceneItem.py b/actions/SceneItem/SceneItem.py index 6ec4e60..dacdff6 100644 --- a/actions/SceneItem/SceneItem.py +++ b/actions/SceneItem/SceneItem.py @@ -11,6 +11,7 @@ # Import gtk modules import gi + gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Gtk, Adw @@ -23,8 +24,12 @@ def __init__(self, *args, **kwargs): self.image_path_map = { State.UNKNOWN: os.path.join(self.plugin_base.PATH, "assets", "error.png"), - State.ENABLED: os.path.join(self.plugin_base.PATH, "assets", "scene_item_enabled.png"), - State.DISABLED: os.path.join(self.plugin_base.PATH, "assets", "scene_item_disabled.png") + State.ENABLED: os.path.join( + self.plugin_base.PATH, "assets", "scene_item_enabled.png" + ), + State.DISABLED: os.path.join( + self.plugin_base.PATH, "assets", "scene_item_disabled.png" + ), } def on_ready(self): @@ -35,11 +40,17 @@ def on_ready(self): self.reconnect_obs() # Show current scene item status - threading.Thread(target=self.show_current_scene_item_status, daemon=True, name="show_current_scene_item_status").start() + threading.Thread( + target=self.show_current_scene_item_status, + daemon=True, + name="show_current_scene_item_status", + ).start() # Copy-paste count: 1 def set_media(self, *args, **kwargs): - super().set_media(media_path=self.image_path_map.get(self.current_state), *args, **kwargs) + super().set_media( + media_path=self.image_path_map.get(self.current_state), *args, **kwargs + ) def show_current_scene_item_status(self): if not self.plugin_base.get_connected(): @@ -53,7 +64,9 @@ def show_current_scene_item_status(self): self.set_media() return - status = self.plugin_base.backend.get_scene_item_enabled(self.get_settings().get("scene"), self.get_settings().get("item")) + status = self.plugin_base.backend.get_scene_item_enabled( + self.get_settings().get("scene"), self.get_settings().get("item") + ) if status is None: self.current_state = State.UNKNOWN self.show_error() @@ -76,10 +89,18 @@ def get_config_rows(self) -> list: super_rows = super().get_config_rows() self.scene_model = Gtk.StringList() - self.scene_row = Adw.ComboRow(model=self.scene_model, title=self.plugin_base.lm.get("actions.switch.scene-row.label")) + self.scene_row = Adw.ComboRow( + model=self.scene_model, + title=self.plugin_base.lm.get("actions.switch.scene-row.label"), + ) self.item_model = Gtk.StringList() - self.item_row = Adw.ComboRow(model=self.item_model, title=self.plugin_base.lm.get("actions.toggle-scene-item-enabled-row.label")) + self.item_row = Adw.ComboRow( + model=self.item_model, + title=self.plugin_base.lm.get( + "actions.toggle-scene-item-enabled-row.label" + ), + ) self.connect_signals() @@ -132,7 +153,11 @@ def load_items_for_scene(self, scene_name): if self.plugin_base.backend.get_connected(): items = self.plugin_base.backend.get_scene_items(scene_name) if items is None: - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join( + self.plugin_base.PATH, "assets", "error.png" + ) + ) return for item in items: self.item_model.append(item) @@ -194,7 +219,9 @@ def on_key_down(self): return next_bool = bool(self.next_state().value) - self.plugin_base.backend.set_scene_item_enabled(scene_name, item_name, next_bool) + self.plugin_base.backend.set_scene_item_enabled( + scene_name, item_name, next_bool + ) self.on_tick() def on_tick(self): diff --git a/actions/SwitchScene/SwitchScene.py b/actions/SwitchScene/SwitchScene.py index 302fe8b..3955e53 100644 --- a/actions/SwitchScene/SwitchScene.py +++ b/actions/SwitchScene/SwitchScene.py @@ -8,18 +8,22 @@ # Import gtk modules import gi + gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Gtk, Adw + class SwitchScene(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - + def on_ready(self): # Connect to obs if not connected if self.plugin_base.backend is not None: - if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if ( + not self.plugin_base.get_connected() + ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() media_path = os.path.join(self.plugin_base.PATH, "assets", "scene.png") @@ -29,7 +33,10 @@ def get_config_rows(self) -> list: super_rows = super().get_config_rows() self.scene_model = Gtk.StringList() - self.scene_row = Adw.ComboRow(model=self.scene_model, title=self.plugin_base.lm.get("actions.switch.scene-row.label")) + self.scene_row = Adw.ComboRow( + model=self.scene_model, + title=self.plugin_base.lm.get("actions.switch.scene-row.label"), + ) self.connect_signals() @@ -38,7 +45,7 @@ def get_config_rows(self) -> list: super_rows.append(self.scene_row) return super_rows - + def connect_signals(self): self.scene_row.connect("notify::selected", self.on_change_scene) @@ -75,7 +82,7 @@ def load_selected_device(self): self.scene_row.set_selected(i) self.connect_signals() return - + self.scene_row.set_selected(Gtk.INVALID_LIST_POSITION) self.connect_signals() @@ -95,4 +102,4 @@ def reconnect_obs(self): super().reconnect_obs() if hasattr(self, "scene_model"): self.load_scene_model() - self.load_configs() \ No newline at end of file + self.load_configs() diff --git a/actions/SwitchSceneCollection/SwitchSceneCollection.py b/actions/SwitchSceneCollection/SwitchSceneCollection.py index b70d068..37531f3 100644 --- a/actions/SwitchSceneCollection/SwitchSceneCollection.py +++ b/actions/SwitchSceneCollection/SwitchSceneCollection.py @@ -8,27 +8,37 @@ # Import gtk modules import gi + gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Gtk, Adw + class SwitchSceneCollection(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - + def on_ready(self): # Connect to obs if not connected if self.plugin_base.backend is not None: - if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if ( + not self.plugin_base.get_connected() + ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "scene.png"), size=0.75) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "scene.png"), + size=0.75, + ) def get_config_rows(self) -> list: super_rows = super().get_config_rows() self.scene_collection_model = Gtk.StringList() - self.scene_collection_row = Adw.ComboRow(model=self.scene_collection_model, title=self.plugin_base.lm.get("actions.switch-scene-collection-row.label")) + self.scene_collection_row = Adw.ComboRow( + model=self.scene_collection_model, + title=self.plugin_base.lm.get("actions.switch-scene-collection-row.label"), + ) self.connect_signals() @@ -37,13 +47,17 @@ def get_config_rows(self) -> list: super_rows.append(self.scene_collection_row) return super_rows - + def connect_signals(self): - self.scene_collection_row.connect("notify::selected", self.on_change_scene_collection) + self.scene_collection_row.connect( + "notify::selected", self.on_change_scene_collection + ) def disconnect_signals(self): try: - self.scene_collection_row.disconnect_by_func(self.on_change_scene_collection) + self.scene_collection_row.disconnect_by_func( + self.on_change_scene_collection + ) except TypeError as e: pass @@ -74,14 +88,16 @@ def load_selected_device(self): self.scene_collection_row.set_selected(i) self.connect_signals() return - + self.scene_collection_row.set_selected(Gtk.INVALID_LIST_POSITION) self.connect_signals() def on_change_scene_collection(self, *args): settings = self.get_settings() selected_index = self.scene_collection_row.get_selected() - settings["scene_collection"] = self.scene_collection_model[selected_index].get_string() + settings["scene_collection"] = self.scene_collection_model[ + selected_index + ].get_string() self.set_settings(settings) def on_key_down(self): @@ -94,4 +110,4 @@ def reconnect_obs(self): super().reconnect_obs() if hasattr(self, "scene_collection_model"): self.load_scene_collection_model() - self.load_configs() \ No newline at end of file + self.load_configs() diff --git a/actions/ToggleRecord/ToggleRecord.py b/actions/ToggleRecord/ToggleRecord.py index 865d7ec..74e7c1b 100644 --- a/actions/ToggleRecord/ToggleRecord.py +++ b/actions/ToggleRecord/ToggleRecord.py @@ -6,6 +6,8 @@ from src.backend.PluginManager.PluginBase import PluginBase import os + + class ToggleRecord(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -15,13 +17,19 @@ def on_ready(self): self.current_state = -1 # Connect to obs if not connected if self.plugin_base.backend is not None: - if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if ( + not self.plugin_base.get_connected() + ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() # Show current rec status - threading.Thread(target=self.show_current_rec_status, daemon=True, name="show_current_rec_status").start() + threading.Thread( + target=self.show_current_rec_status, + daemon=True, + name="show_current_rec_status", + ).start() - def show_current_rec_status(self, new_paused = False): + def show_current_rec_status(self, new_paused=False): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() @@ -54,7 +62,7 @@ def show_for_state(self, state: int): if state == self.current_state: return - + self.current_state = state image = "record_inactive.png" if state == 0: @@ -84,13 +92,17 @@ def on_tick(self): def show_rec_time(self): if not self.plugin_base.backend.get_connected(): - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return status = self.plugin_base.backend.get_record_status() if status is None: - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if not status["active"]: self.set_bottom_label(None) return - self.set_bottom_label(status["timecode"][:-4], font_size=16) \ No newline at end of file + self.set_bottom_label(status["timecode"][:-4], font_size=16) diff --git a/actions/ToggleReplayBuffer/ToggleReplayBuffer.py b/actions/ToggleReplayBuffer/ToggleReplayBuffer.py index a5550d3..0895284 100644 --- a/actions/ToggleReplayBuffer/ToggleReplayBuffer.py +++ b/actions/ToggleReplayBuffer/ToggleReplayBuffer.py @@ -6,6 +6,8 @@ from src.backend.PluginManager.PluginBase import PluginBase import os + + class ToggleReplayBuffer(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -15,28 +17,40 @@ def on_ready(self): self.current_state = -1 # Connect to obs if not connected if self.plugin_base.backend is not None: - if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if ( + not self.plugin_base.get_connected() + ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() # Show current replay buffer status - threading.Thread(target=self.show_current_replay_buffer_status, daemon=True, name="show_current_replay_buffer_status").start() + threading.Thread( + target=self.show_current_replay_buffer_status, + daemon=True, + name="show_current_replay_buffer_status", + ).start() - def show_current_replay_buffer_status(self, new_paused = False): + def show_current_replay_buffer_status(self, new_paused=False): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if not self.plugin_base.backend.get_connected(): self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return status = self.plugin_base.backend.get_replay_buffer_status() if status is None: self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if status["active"]: self.show_for_state(1) @@ -50,7 +64,7 @@ def show_for_state(self, state: int): """ if state == self.current_state: return - + self.current_state = state image = "replay_buffer_disabled.png" if state == 0: @@ -64,12 +78,16 @@ def on_key_down(self): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if not self.plugin_base.backend.get_connected(): self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if self.current_state == 0: self.plugin_base.backend.start_replay_buffer() @@ -78,4 +96,4 @@ def on_key_down(self): self.on_tick() def on_tick(self): - self.show_current_replay_buffer_status() \ No newline at end of file + self.show_current_replay_buffer_status() diff --git a/actions/ToggleStream/ToggleStream.py b/actions/ToggleStream/ToggleStream.py index 897391d..7271b9d 100644 --- a/actions/ToggleStream/ToggleStream.py +++ b/actions/ToggleStream/ToggleStream.py @@ -6,20 +6,26 @@ from src.backend.PluginManager.PluginBase import PluginBase import os + + class ToggleStream(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.current_state = -1 - + def on_ready(self): self.current_state = -1 if self.plugin_base.backend is None: if not self.plugin_base.get_connected(): self.reconnect_obs() - - threading.Thread(target=self.show_current_stream_status, daemon=True, name="show_current_stream_status").start() - - def show_current_stream_status(self, new_paused = False): + + threading.Thread( + target=self.show_current_stream_status, + daemon=True, + name="show_current_stream_status", + ).start() + + def show_current_stream_status(self, new_paused=False): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() @@ -41,7 +47,7 @@ def show_current_stream_status(self, new_paused = False): self.show_for_state(1) else: self.show_for_state(0) - + def show_for_state(self, state: int): """ 0: Not Streaming @@ -50,10 +56,10 @@ def show_for_state(self, state: int): """ if state in [1, 2]: self.show_stream_time() - + if state == self.current_state: return - + self.current_state = state image = "stream_inactive.png" if state == 0: @@ -62,9 +68,9 @@ def show_for_state(self, state: int): image = "stream_active.png" elif state == 2: image = "stream_reconnecting.png" - + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", image)) - + def on_key_down(self): if self.plugin_base.backend is None: self.current_state = -1 @@ -76,20 +82,24 @@ def on_key_down(self): return self.plugin_base.backend.toggle_stream() self.on_tick() - + def on_tick(self): self.show_current_stream_status() - + def show_stream_time(self): if not self.plugin_base.backend.get_connected(): - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return status = self.plugin_base.backend.get_stream_status() if status is None: - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return - + if not status["active"]: self.set_bottom_label(None) return - self.set_bottom_label(status["timecode"][:-4]) \ No newline at end of file + self.set_bottom_label(status["timecode"][:-4]) diff --git a/actions/ToggleStudioMode/ToggleStudioMode.py b/actions/ToggleStudioMode/ToggleStudioMode.py index 117c210..48cdf38 100644 --- a/actions/ToggleStudioMode/ToggleStudioMode.py +++ b/actions/ToggleStudioMode/ToggleStudioMode.py @@ -6,6 +6,8 @@ from src.backend.PluginManager.PluginBase import PluginBase import os + + class ToggleStudioMode(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -15,28 +17,40 @@ def on_ready(self): self.current_state = -1 # Connect to obs if not connected if self.plugin_base.backend is not None: - if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if ( + not self.plugin_base.get_connected() + ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() # Show current studio mode status - threading.Thread(target=self.show_current_studio_mode_status, daemon=True, name="show_current_studio_mode_status").start() + threading.Thread( + target=self.show_current_studio_mode_status, + daemon=True, + name="show_current_studio_mode_status", + ).start() - def show_current_studio_mode_status(self, new_paused = False): + def show_current_studio_mode_status(self, new_paused=False): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if not self.plugin_base.backend.get_connected(): self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return status = self.plugin_base.backend.get_studio_mode_enabled() if status is None: self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if status["active"]: self.show_for_state(1) @@ -50,7 +64,7 @@ def show_for_state(self, state: int): """ if state == self.current_state: return - + self.current_state = state image = "studio_mode_disabled.png" if state == 0: @@ -64,12 +78,16 @@ def on_key_down(self): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if not self.plugin_base.backend.get_connected(): self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if self.current_state == 0: self.plugin_base.backend.set_studio_mode_enabled(True) @@ -78,4 +96,4 @@ def on_key_down(self): self.on_tick() def on_tick(self): - self.show_current_studio_mode_status() \ No newline at end of file + self.show_current_studio_mode_status() diff --git a/actions/ToggleVirtualCamera/ToggleVirtualCamera.py b/actions/ToggleVirtualCamera/ToggleVirtualCamera.py index 400e11f..afb850d 100644 --- a/actions/ToggleVirtualCamera/ToggleVirtualCamera.py +++ b/actions/ToggleVirtualCamera/ToggleVirtualCamera.py @@ -6,6 +6,8 @@ from src.backend.PluginManager.PluginBase import PluginBase import os + + class ToggleVirtualCamera(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -15,28 +17,40 @@ def on_ready(self): self.current_state = -1 # Connect to obs if not connected if self.plugin_base.backend is not None: - if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if ( + not self.plugin_base.get_connected() + ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() # Show current virtual camera status - threading.Thread(target=self.show_current_virtual_camera_status, daemon=True, name="show_current_virtual_camera_status").start() + threading.Thread( + target=self.show_current_virtual_camera_status, + daemon=True, + name="show_current_virtual_camera_status", + ).start() - def show_current_virtual_camera_status(self, new_paused = False): + def show_current_virtual_camera_status(self, new_paused=False): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if not self.plugin_base.backend.get_connected(): self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return status = self.plugin_base.backend.get_virtual_camera_status() if status is None: self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if status["active"]: self.show_for_state(1) @@ -50,7 +64,7 @@ def show_for_state(self, state: int): """ if state == self.current_state: return - + self.current_state = state image = "virtual_camera_disabled.png" if state == 0: @@ -58,18 +72,24 @@ def show_for_state(self, state: int): elif state == 1: image = "virtual_camera_enabled.png" - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", image), size=0.75) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", image), size=0.75 + ) def on_key_down(self): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if not self.plugin_base.backend.get_connected(): self.current_state = -1 self.show_error() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") + ) return if self.current_state == 0: self.plugin_base.backend.start_virtual_camera() @@ -78,4 +98,4 @@ def on_key_down(self): self.on_tick() def on_tick(self): - self.show_current_virtual_camera_status() \ No newline at end of file + self.show_current_virtual_camera_status() diff --git a/actions/TriggerTransition/TriggerTransition.py b/actions/TriggerTransition/TriggerTransition.py index 6a9fe8c..bdbde98 100644 --- a/actions/TriggerTransition/TriggerTransition.py +++ b/actions/TriggerTransition/TriggerTransition.py @@ -6,6 +6,8 @@ from src.backend.PluginManager.PluginBase import PluginBase import os + + class TriggerTransition(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -13,9 +15,14 @@ def __init__(self, *args, **kwargs): def on_ready(self): # Connect to obs if not connected if self.plugin_base.backend is not None: - if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if ( + not self.plugin_base.get_connected() + ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() - self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "transition.png"), size=0.85) + self.set_media( + media_path=os.path.join(self.plugin_base.PATH, "assets", "transition.png"), + size=0.85, + ) def on_key_down(self): if self.plugin_base.backend is None: @@ -24,4 +31,4 @@ def on_key_down(self): if not self.plugin_base.backend.get_connected(): self.show_error() return - self.plugin_base.backend.trigger_transition() \ No newline at end of file + self.plugin_base.backend.trigger_transition() diff --git a/actions/mixins/MixinBase.py b/actions/mixins/MixinBase.py index 43ac50b..d31202c 100644 --- a/actions/mixins/MixinBase.py +++ b/actions/mixins/MixinBase.py @@ -28,7 +28,9 @@ def current_state(self) -> State: @current_state.setter def current_state(self, val: int | State): if not val in State: - log.warning(f"current_state setter called with non-State type {type(val)=} {val=}.") + log.warning( + f"current_state setter called with non-State type {type(val)=} {val=}." + ) val = State(val) self._current_state = val diff --git a/actions/mixins/SetMixin.py b/actions/mixins/SetMixin.py index 36956dd..7e2a9ea 100644 --- a/actions/mixins/SetMixin.py +++ b/actions/mixins/SetMixin.py @@ -17,11 +17,16 @@ def __init__(self, set_mixin: "SetMixin"): self.input_model = Gtk.StringList() self.input_row = Adw.ComboRow( - model=self.input_model, title=set_mixin.plugin_base.lm.get("actions.mixins.set.label") + model=self.input_model, + title=set_mixin.plugin_base.lm.get("actions.mixins.set.label"), ) - self.input_model.append(set_mixin.plugin_base.lm.get("actions.mixins.set.enable")) - self.input_model.append(set_mixin.plugin_base.lm.get("actions.mixins.set.disable")) + self.input_model.append( + set_mixin.plugin_base.lm.get("actions.mixins.set.enable") + ) + self.input_model.append( + set_mixin.plugin_base.lm.get("actions.mixins.set.disable") + ) self.input_row.connect("notify::selected", self.on_select) diff --git a/backend/OBSController.py b/backend/OBSController.py index 2dea994..8c10cc0 100644 --- a/backend/OBSController.py +++ b/backend/OBSController.py @@ -5,10 +5,13 @@ import socket import ipaddress + class OBSController(obsws): def __init__(self): self.connected = False - self.event_obs: obsws = None # All events are connected to this to avoid crash if a request is made in an event + self.event_obs: obsws = ( + None # All events are connected to this to avoid crash if a request is made in an event + ) pass def validate_dns(self, host: str) -> bool: @@ -30,7 +33,7 @@ def validate_dns(self, host: str) -> bool: return True # Split into labels and validate each - labels = host.split('.') + labels = host.split(".") if not labels: return False @@ -49,7 +52,7 @@ def validate_dns(self, host: str) -> bool: return False # Middle characters can be alphanumeric or hyphen for char in label: - if not (char.isalnum() or char == '-'): + if not (char.isalnum() or char == "-"): return False return True @@ -66,7 +69,7 @@ def validate_ip(self, host: str): host = host.strip() # Handle bracket-wrapped IPv6 addresses [::1] - if host.startswith('[') and host.endswith(']'): + if host.startswith("[") and host.endswith("]"): host = host[1:-1] # Try to parse as IP address (IPv4 or IPv6) @@ -92,7 +95,11 @@ def register(self, *args, **kwargs): """ try: self.event_obs.register(*args, **kwargs) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def connect_to(self, host=None, port=None, timeout=1, legacy=False, **kwargs): @@ -112,7 +119,7 @@ def connect_to(self, host=None, port=None, timeout=1, legacy=False, **kwargs): addr = ipaddress.ip_address(host) if isinstance(addr, ipaddress.IPv6Address): # Only wrap if not already wrapped - if not (host.startswith('[') and host.endswith(']')): + if not (host.startswith("[") and host.endswith("]")): connection_host = f"[{host}]" log.debug(f"Wrapped IPv6 address: {host} -> {connection_host}") except ValueError: @@ -121,16 +128,54 @@ def connect_to(self, host=None, port=None, timeout=1, legacy=False, **kwargs): try: log.debug(f"Trying to connect to obs with legacy: {legacy}") - super().__init__(host=connection_host, port=port, timeout=timeout, legacy=legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) - self.event_obs = obsws(host=connection_host, port=port, timeout=timeout, legacy=legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) + super().__init__( + host=connection_host, + port=port, + timeout=timeout, + legacy=legacy, + on_connect=self.on_connect, + on_disconnect=self.on_disconnect, + authreconnect=5, + **kwargs, + ) + self.event_obs = obsws( + host=connection_host, + port=port, + timeout=timeout, + legacy=legacy, + on_connect=self.on_connect, + on_disconnect=self.on_disconnect, + authreconnect=5, + **kwargs, + ) self.connect() log.info("Successfully connected to OBS") return True except (obswebsocket.exceptions.ConnectionFailure, ValueError) as e: try: - log.error(f"Failed to connect to OBS with legacy: {legacy}, trying with legacy: {not legacy}") - super().__init__(host=connection_host, port=port, timeout=timeout, legacy=not legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) - self.event_obs = obsws(host=connection_host, port=port, timeout=timeout, legacy=not legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) + log.error( + f"Failed to connect to OBS with legacy: {legacy}, trying with legacy: {not legacy}" + ) + super().__init__( + host=connection_host, + port=port, + timeout=timeout, + legacy=not legacy, + on_connect=self.on_connect, + on_disconnect=self.on_disconnect, + authreconnect=5, + **kwargs, + ) + self.event_obs = obsws( + host=connection_host, + port=port, + timeout=timeout, + legacy=not legacy, + on_connect=self.on_connect, + on_disconnect=self.on_disconnect, + authreconnect=5, + **kwargs, + ) self.connect() log.info("Successfully connected to OBS") @@ -138,18 +183,25 @@ def connect_to(self, host=None, port=None, timeout=1, legacy=False, **kwargs): except (obswebsocket.exceptions.ConnectionFailure, ValueError) as e: log.error(f"Failed to connect to OBS: {e}") - ## Streaming def start_stream(self) -> None: try: self.call(requests.StartStream()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def stop_stream(self) -> None: try: self.call(requests.StopStream()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def toggle_stream(self): @@ -158,7 +210,11 @@ def toggle_stream(self): """ try: self.call(requests.ToggleStream()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def get_stream_status(self) -> bool: @@ -174,33 +230,52 @@ def get_stream_status(self) -> bool: """ try: return self.call(requests.GetStreamStatus()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) - def send_stream_caption(self, caption:str): + def send_stream_caption(self, caption: str): try: self.call(requests.SendStreamCaption(caption=caption)) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) - ## Recording def start_record(self) -> None: try: return self.call(requests.StartRecord()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def pause_record(self): try: return self.call(requests.PauseRecord()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def resume_record(self): try: return self.call(requests.ResumeRecord()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def stop_recording(self) -> None: @@ -209,7 +284,11 @@ def stop_recording(self) -> None: """ try: return self.call(requests.StopRecord()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def get_record_status(self): @@ -222,22 +301,33 @@ def get_record_status(self): """ try: return self.call(requests.GetRecordStatus()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def toggle_record(self): try: return self.call(requests.ToggleRecord()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def toggle_record_pause(self): try: return self.call(requests.ToggleRecordPause()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) - ## Replay Buffer def get_replay_buffer_status(self): """ @@ -251,28 +341,43 @@ def get_replay_buffer_status(self): return else: return request - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def start_replay_buffer(self): try: return self.call(requests.StartReplayBuffer()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def stop_replay_buffer(self): try: return self.call(requests.StopReplayBuffer()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def save_replay_buffer(self): try: return self.call(requests.SaveReplayBuffer()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) - ## Virtual Camera def get_virtual_camera_status(self): """ @@ -286,19 +391,31 @@ def get_virtual_camera_status(self): return else: return request - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def start_virtual_camera(self): try: return self.call(requests.StartVirtualCam()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def stop_virtual_camera(self): try: return self.call(requests.StopVirtualCam()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) ## Studio Mode @@ -308,28 +425,43 @@ def get_studio_mode_enabled(self): """ try: return self.call(requests.GetStudioModeEnabled()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) - def set_studio_mode_enabled(self, enabled:bool): + def set_studio_mode_enabled(self, enabled: bool): try: return self.call(requests.SetStudioModeEnabled(studioModeEnabled=enabled)) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def trigger_transition(self): try: return self.call(requests.TriggerStudioModeTransition()) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) - ## Input mixer def get_inputs(self) -> list: try: inputs = self.call(requests.GetInputList()).getInputs() return [input["inputName"] for input in inputs] - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def get_input_muted(self, input: str) -> None: @@ -344,13 +476,21 @@ def get_input_muted(self, input: str) -> None: return else: return request - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def set_input_muted(self, input: str, muted: bool) -> None: try: self.call(requests.SetInputMute(inputName=input, inputMuted=muted)) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def get_input_volume(self, input: str): @@ -362,22 +502,35 @@ def get_input_volume(self, input: str): return else: return request - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def set_input_volume(self, input: str, volume: int) -> None: try: self.call(requests.SetInputVolume(inputName=input, inputVolumeDb=volume)) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) - ## Scene Items def get_scene_items(self, sceneName: str) -> list: try: - sceneItems = self.call(requests.GetSceneItemList(sceneName=sceneName)).getSceneItems() + sceneItems = self.call( + requests.GetSceneItemList(sceneName=sceneName) + ).getSceneItems() return [sceneItem["sourceName"] for sceneItem in sceneItems] - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def get_scene_item_enabled(self, sceneName: str, sourceName: str) -> None: @@ -385,74 +538,145 @@ def get_scene_item_enabled(self, sceneName: str, sourceName: str) -> None: sceneItemEnabled: bool -> Whether the scene item is enabled. true for enabled, false for disabled """ try: - sceneItemId = self.call(requests.GetSceneItemId(sceneName=sceneName, sourceName=sourceName)).getSceneItemId() - return self.call(requests.GetSceneItemEnabled(sceneName=sceneName, sceneItemId=sceneItemId)) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + sceneItemId = self.call( + requests.GetSceneItemId(sceneName=sceneName, sourceName=sourceName) + ).getSceneItemId() + return self.call( + requests.GetSceneItemEnabled( + sceneName=sceneName, sceneItemId=sceneItemId + ) + ) + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: if str(e) == "'sceneItemId'": log.warning("Cannot find the scene item!") else: log.error(e) - def set_scene_item_enabled(self, sceneName: str, sourceName: str, enabled: bool) -> None: - try: - sceneItemId = self.call(requests.GetSceneItemId(sceneName=sceneName, sourceName=sourceName)).getSceneItemId() - self.call(requests.SetSceneItemEnabled(sceneName=sceneName, sceneItemId=sceneItemId, sceneItemEnabled=enabled)) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + def set_scene_item_enabled( + self, sceneName: str, sourceName: str, enabled: bool + ) -> None: + try: + sceneItemId = self.call( + requests.GetSceneItemId(sceneName=sceneName, sourceName=sourceName) + ).getSceneItemId() + self.call( + requests.SetSceneItemEnabled( + sceneName=sceneName, + sceneItemId=sceneItemId, + sceneItemEnabled=enabled, + ) + ) + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) - ## Scenes def get_scenes(self) -> list: try: scenes = self.call(requests.GetSceneList()).getScenes() return [scene["sceneName"] for scene in scenes] - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) ## Credit for Studio Mode Preview fix: Rinma (https://github.com/Rinma) - def switch_to_scene(self, scene:str) -> None: + def switch_to_scene(self, scene: str) -> None: studioModeStatus = self.get_studio_mode_enabled() if studioModeStatus.datain["studioModeEnabled"]: try: self.call(requests.SetCurrentPreviewScene(sceneName=scene)) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) else: try: self.call(requests.SetCurrentProgramScene(sceneName=scene)) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) ## Scene Collections def get_scene_collections(self) -> list: try: - sceneCollections = self.call(requests.GetSceneCollectionList()).getSceneCollections() + sceneCollections = self.call( + requests.GetSceneCollectionList() + ).getSceneCollections() return sceneCollections - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def set_current_scene_collection(self, sceneCollectionName: str) -> None: try: - self.call(requests.SetCurrentSceneCollection(sceneCollectionName=sceneCollectionName)) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + self.call( + requests.SetCurrentSceneCollection( + sceneCollectionName=sceneCollectionName + ) + ) + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def get_source_filters(self, sourceName: str) -> list: try: - source_filters = self.call(requests.GetSourceFilterList(sourceName=sourceName)).getfilters() + source_filters = self.call( + requests.GetSourceFilterList(sourceName=sourceName) + ).getfilters() return source_filters - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) - def set_source_filter_enabled(self, sourceName: str, filterName: str, enabled: bool) -> None: + def set_source_filter_enabled( + self, sourceName: str, filterName: str, enabled: bool + ) -> None: try: - self.call(requests.SetSourceFilterEnabled(sourceName=sourceName, filterName=filterName, filterEnabled=enabled)) - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + self.call( + requests.SetSourceFilterEnabled( + sourceName=sourceName, filterName=filterName, filterEnabled=enabled + ) + ) + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) def get_source_filter(self, sourceName: str, filterName: str) -> None: try: - source_filter = self.call(requests.GetSourceFilter(sourceName=sourceName, filterName=filterName)).datain + source_filter = self.call( + requests.GetSourceFilter(sourceName=sourceName, filterName=filterName) + ).datain return source_filter - except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: + except ( + obswebsocket.exceptions.MessageTimeout, + websocket._exceptions.WebSocketConnectionClosedException, + KeyError, + ) as e: log.error(e) diff --git a/backend/backend.py b/backend/backend.py index e14eafc..8205c56 100644 --- a/backend/backend.py +++ b/backend/backend.py @@ -1,4 +1,5 @@ import logging + LOG = logging.getLogger(__name__) # Set the logger level to ERROR LOG.setLevel(logging.ERROR) @@ -14,6 +15,7 @@ import os import threading + class Backend(BackendBase): def __init__(self): super().__init__() @@ -21,7 +23,7 @@ def __init__(self): self.OBSController.connect_to( host=self.frontend.get_settings().get("ip", "localhost"), port=self.frontend.get_settings().get("port", 4455), - password=self.frontend.get_settings().get("password") or "" + password=self.frontend.get_settings().get("password") or "", ) """ @@ -54,7 +56,7 @@ def get_stream_status(self) -> dict: "congestion": status.datain["outputCongestion"], "bytes": status.datain["outputBytes"], "skipped_frames": status.datain["outputSkippedFrames"], - "total_frames": status.datain["outputTotalFrames"] + "total_frames": status.datain["outputTotalFrames"], } def toggle_stream(self): @@ -62,7 +64,7 @@ def toggle_stream(self): if status is None: return False return status.datain["outputActive"] - + # Recording def get_record_status(self) -> dict: status = self.OBSController.get_record_status() @@ -73,7 +75,7 @@ def get_record_status(self) -> dict: "paused": status.datain["outputPaused"], "timecode": status.datain["outputTimecode"], "duration": status.datain["outputDuration"], - "bytes": status.datain["outputBytes"] + "bytes": status.datain["outputBytes"], } def toggle_record(self): @@ -87,9 +89,7 @@ def get_replay_buffer_status(self) -> dict: status = self.OBSController.get_replay_buffer_status() if status is None: return - return { - "active": status.datain["outputActive"] - } + return {"active": status.datain["outputActive"]} def start_replay_buffer(self): self.OBSController.start_replay_buffer() @@ -105,9 +105,7 @@ def get_virtual_camera_status(self) -> dict: status = self.OBSController.get_virtual_camera_status() if status is None: return - return { - "active": status.datain["outputActive"] - } + return {"active": status.datain["outputActive"]} def start_virtual_camera(self): self.OBSController.start_virtual_camera() @@ -120,9 +118,7 @@ def get_studio_mode_enabled(self) -> dict: status = self.OBSController.get_studio_mode_enabled() if status is None: return - return { - "active": status.datain["studioModeEnabled"] - } + return {"active": status.datain["studioModeEnabled"]} def set_studio_mode_enabled(self, enabled: bool): self.OBSController.set_studio_mode_enabled(enabled) @@ -138,9 +134,7 @@ def get_input_muted(self, input: str): status = self.OBSController.get_input_muted(input) if status is None: return - return { - "muted": status.datain["inputMuted"] - } + return {"muted": status.datain["inputMuted"]} def set_input_muted(self, input: str, muted: bool): self.OBSController.set_input_muted(input, muted) @@ -149,9 +143,7 @@ def get_input_volume(self, input: str): status = self.OBSController.get_input_volume(input) if status is None: return - return { - "volume": status.datain["inputVolumeDb"] - } + return {"volume": status.datain["inputVolumeDb"]} def set_input_volume(self, input: str, volume: int): self.OBSController.set_input_volume(input, volume) @@ -159,8 +151,8 @@ def set_input_volume(self, input: str, volume: int): # Scenes def get_scene_names(self) -> list[str]: return self.OBSController.get_scenes() - - def switch_to_scene(self, scene:str): + + def switch_to_scene(self, scene: str): self.OBSController.switch_to_scene(scene) # Scene Items @@ -171,9 +163,7 @@ def get_scene_item_enabled(self, sceneName: str, sourceName: str): status = self.OBSController.get_scene_item_enabled(sceneName, sourceName) if status is None: return - return { - "enabled": status.datain["sceneItemEnabled"] - } + return {"enabled": status.datain["sceneItemEnabled"]} def set_scene_item_enabled(self, sceneName: str, sourceName: str, enabled: bool): self.OBSController.set_scene_item_enabled(sceneName, sourceName, enabled) @@ -184,14 +174,17 @@ def get_scene_collections(self) -> list[str]: def set_current_scene_collection(self, sceneCollectionName: str): return self.OBSController.set_current_scene_collection(sceneCollectionName) - + def get_source_filters(self, sourceName: str) -> list: return self.OBSController.get_source_filters(sourceName) - - def set_source_filter_enabled(self, sourceName: str, filterName: str, enabled: bool): + + def set_source_filter_enabled( + self, sourceName: str, filterName: str, enabled: bool + ): self.OBSController.set_source_filter_enabled(sourceName, filterName, enabled) def get_source_filter(self, sourceName: str, filterName: str) -> None: return self.OBSController.get_source_filter(sourceName, filterName) - -backend = Backend() \ No newline at end of file + + +backend = Backend() From d1db64e9af6cdce451c99b5b36c19c61d971542e Mon Sep 17 00:00:00 2001 From: Malte Moersener Date: Mon, 20 Oct 2025 13:17:11 +0200 Subject: [PATCH 5/5] Revert "chore: linting" This reverts commit bb988f5dc562a0cc33cfc72c474797e6ac0afc66. --- OBSActionBase.py | 31 +- __install__.py | 4 +- actions/Filter/FilterBase.py | 43 +- actions/InputDial/InputDial.py | 102 ++--- actions/InputMute/InputMuteBase.py | 33 +- actions/RecPlayPause/RecPlayPause.py | 11 +- actions/SaveReplayBuffer/SaveReplayBuffer.py | 16 +- actions/SceneItem/SceneItem.py | 45 +-- actions/SwitchScene/SwitchScene.py | 19 +- .../SwitchSceneCollection.py | 36 +- actions/ToggleRecord/ToggleRecord.py | 26 +- .../ToggleReplayBuffer/ToggleReplayBuffer.py | 38 +- actions/ToggleStream/ToggleStream.py | 42 +- actions/ToggleStudioMode/ToggleStudioMode.py | 38 +- .../ToggleVirtualCamera.py | 42 +- .../TriggerTransition/TriggerTransition.py | 13 +- actions/mixins/MixinBase.py | 4 +- actions/mixins/SetMixin.py | 11 +- backend/OBSController.py | 368 ++++-------------- backend/backend.py | 51 +-- 20 files changed, 248 insertions(+), 725 deletions(-) diff --git a/OBSActionBase.py b/OBSActionBase.py index 80faa06..a2de89a 100644 --- a/OBSActionBase.py +++ b/OBSActionBase.py @@ -21,22 +21,17 @@ def __init__(self, *args, **kwargs): self.has_configuration = True self.status_label = Gtk.Label( - label=self.plugin_base.lm.get("actions.base.status.no-connection"), - css_classes=["bold", "red"], + label=self.plugin_base.lm.get("actions.base.status.no-connection"), css_classes=["bold", "red"] ) if not self.plugin_base.backend.get_connected(): self.reconnect_obs() def get_config_rows(self) -> list: - self.ip_entry = Adw.EntryRow( - title=self.plugin_base.lm.get("actions.base.ip.label") - ) + self.ip_entry = Adw.EntryRow(title=self.plugin_base.lm.get("actions.base.ip.label")) self.port_spinner = Adw.SpinRow.new_with_range(0, 65535, 1) self.port_spinner.set_title(self.plugin_base.lm.get("actions.base.port.label")) - self.password_entry = Adw.PasswordEntryRow( - title=self.plugin_base.lm.get("actions.base.password.label") - ) + self.password_entry = Adw.PasswordEntryRow(title=self.plugin_base.lm.get("actions.base.password.label")) self.load_config_defaults() @@ -69,9 +64,7 @@ def on_change_ip(self, entry, *args): self.reconnect_obs() def update_ip_warning_status(self): - valid = self.plugin_base.backend.OBSController.validate_ip( - self.ip_entry.get_text().strip() - ) + valid = self.plugin_base.backend.OBSController.validate_ip(self.ip_entry.get_text().strip()) if valid: self.ip_entry.remove_css_class("error") else: @@ -92,9 +85,7 @@ def on_change_password(self, entry, *args): self.reconnect_obs() def reconnect_obs(self): - threading.Thread( - target=self._reconnect_obs, daemon=True, name="reconnect_obs" - ).start() + threading.Thread(target=self._reconnect_obs, daemon=True, name="reconnect_obs").start() def _reconnect_obs(self): try: @@ -112,23 +103,17 @@ def _reconnect_obs(self): self.update_status_label() def update_status_label(self) -> None: - threading.Thread( - target=self._update_status_label, daemon=True, name="update_status_label" - ).start() + threading.Thread(target=self._update_status_label, daemon=True, name="update_status_label").start() def _update_status_label(self): if self.plugin_base.backend.get_connected(): print("connected - label") - self.status_label.set_label( - self.plugin_base.lm.get("actions.base.status.connected") - ) + self.status_label.set_label(self.plugin_base.lm.get("actions.base.status.connected")) self.status_label.remove_css_class("red") self.status_label.add_css_class("green") else: print("not connected - label") - self.status_label.set_label( - self.plugin_base.lm.get("actions.base.status.no-connection") - ) + self.status_label.set_label(self.plugin_base.lm.get("actions.base.status.no-connection")) self.status_label.remove_css_class("green") self.status_label.add_css_class("red") diff --git a/__install__.py b/__install__.py index 4c7d678..5a1a84f 100644 --- a/__install__.py +++ b/__install__.py @@ -2,6 +2,4 @@ from os.path import join, abspath, dirname toplevel = dirname(abspath(__file__)) -create_venv( - join(toplevel, "backend", ".venv"), join(toplevel, "backend", "requirements.txt") -) +create_venv(join(toplevel, "backend", ".venv"), join(toplevel, "backend", "requirements.txt")) diff --git a/actions/Filter/FilterBase.py b/actions/Filter/FilterBase.py index b597a06..9933c4b 100644 --- a/actions/Filter/FilterBase.py +++ b/actions/Filter/FilterBase.py @@ -10,7 +10,6 @@ # Import gtk modules import gi - gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Gtk, Adw @@ -29,11 +28,7 @@ def on_ready(self): self.reconnect_obs() # Show current scene filter status - threading.Thread( - target=self.show_current_filter_status, - daemon=True, - name="show_current_filter_status", - ).start() + threading.Thread(target=self.show_current_filter_status, daemon=True, name="show_current_filter_status").start() def show_current_filter_status(self): if not self.plugin_base.get_connected(): @@ -45,9 +40,7 @@ def show_current_filter_status(self): self.show_error() return - status = self.plugin_base.backend.get_source_filter( - self.get_settings().get("scene"), self.get_settings().get("filter") - ) + status = self.plugin_base.backend.get_source_filter(self.get_settings().get("scene"), self.get_settings().get("filter")) if status is None: self.current_state = State.UNKNOWN self.show_error() @@ -74,26 +67,16 @@ def show_for_state(self, state: State): elif state == State.ENABLED: image = "scene_item_enabled.png" - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", image), size=0.75 - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", image), size=0.75) def get_config_rows(self) -> list: super_rows = super().get_config_rows() self.scene_model = Gtk.StringList() - self.scene_row = Adw.ComboRow( - model=self.scene_model, - title=self.plugin_base.lm.get("actions.switch.scene-row.label"), - ) + self.scene_row = Adw.ComboRow(model=self.scene_model, title=self.plugin_base.lm.get("actions.switch.scene-row.label")) self.filter_model = Gtk.StringList() - self.filter_row = Adw.ComboRow( - model=self.filter_model, - title=self.plugin_base.lm.get( - "actions.toggle-scene-filter-enabled-row.label" - ), - ) + self.filter_row = Adw.ComboRow(model=self.filter_model, title=self.plugin_base.lm.get("actions.toggle-scene-filter-enabled-row.label")) self.connect_signals() @@ -195,28 +178,20 @@ def on_key_down(self): if not self.plugin_base.get_connected(): self.current_state = State.UNKNOWN self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return scene_name = self.get_settings().get("scene") filter_name = self.get_settings().get("filter") if scene_name in [None, ""]: - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if filter_name in [None, ""]: - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return next_state = bool(self.next_state().value) - self.plugin_base.backend.set_source_filter_enabled( - scene_name, filter_name, next_state - ) + self.plugin_base.backend.set_source_filter_enabled(scene_name, filter_name, next_state) self.on_tick() def on_tick(self): diff --git a/actions/InputDial/InputDial.py b/actions/InputDial/InputDial.py index e98db99..82ae407 100644 --- a/actions/InputDial/InputDial.py +++ b/actions/InputDial/InputDial.py @@ -11,12 +11,10 @@ # Import gtk modules import gi - gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Gtk, Adw - class InputDial(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -30,62 +28,44 @@ def on_ready(self): if self.plugin_base.backend is not None: if not self.plugin_base.get_connected(): self.reconnect_obs() - + # Show current input volume self.muted = None self.volume = None - threading.Thread( - target=self.show_current_input_volume, - daemon=True, - name="show_current_input_volume", - ).start() - + threading.Thread(target=self.show_current_input_volume, daemon=True, name="show_current_input_volume").start() + def show_current_input_volume(self): if self.plugin_base.backend is None: self.current_state = None self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if not self.plugin_base.backend.get_connected(): self.current_state = None self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if not self.get_settings().get("input"): self.current_state = None self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return - + # update muted - status = self.plugin_base.backend.get_input_muted( - self.get_settings().get("input") - ) + status = self.plugin_base.backend.get_input_muted(self.get_settings().get("input")) if status is None: self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return self.muted = status["muted"] # update volume - status = self.plugin_base.backend.get_input_volume( - self.get_settings().get("input") - ) + status = self.plugin_base.backend.get_input_volume(self.get_settings().get("input")) if status is None: self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return self.volume = self.db_to_volume(status["volume"]) @@ -95,10 +75,7 @@ def show_current_input_volume(self): if self.last_muted != self.muted: self.last_muted = self.muted - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", image), - size=0.9, - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", image), size=0.9) if self.last_volume != self.volume: self.last_volume = self.volume self.set_label(label) @@ -107,10 +84,7 @@ def get_config_rows(self) -> list: super_rows = super().get_config_rows() self.input_model = Gtk.StringList() - self.input_row = Adw.ComboRow( - model=self.input_model, - title=self.plugin_base.lm.get("actions.input-dial-row.label"), - ) + self.input_row = Adw.ComboRow(model=self.input_model, title=self.plugin_base.lm.get("actions.input-dial-row.label")) self.connect_signals() @@ -128,7 +102,7 @@ def disconnect_signals(self): self.input_row.disconnect_by_func(self.on_input_change) except TypeError as e: pass - + def load_input_model(self): self.disconnect_signals() # Clear model @@ -139,11 +113,7 @@ def load_input_model(self): if self.plugin_base.backend.get_connected(): inputs = self.plugin_base.backend.get_inputs() if inputs is None: - self.set_media( - media_path=os.path.join( - self.plugin_base.PATH, "assets", "error.png" - ) - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return for input in inputs: self.input_model.append(input) @@ -161,10 +131,10 @@ def load_selected_device(self): self.input_row.set_selected(i) self.connect_signals() return - + self.input_row.set_selected(Gtk.INVALID_LIST_POSITION) self.connect_signals() - + def on_input_change(self, *args): settings = self.get_settings() selected_index = self.input_row.get_selected() @@ -183,60 +153,46 @@ def mute_toggle(self): if self.plugin_base.backend is None: self.current_state = None self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if not self.plugin_base.backend.get_connected(): self.current_state = None self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return input_name = self.get_settings().get("input") if input_name in [None, ""]: - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return self.muted = not self.muted self.plugin_base.backend.set_input_muted(input_name, self.muted) self.on_tick() - + def volume_change(self, diff): if self.plugin_base.backend is None: self.current_state = None self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if not self.plugin_base.backend.get_connected(): self.current_state = None self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return input_name = self.get_settings().get("input") if input_name in [None, ""]: - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return - + self.volume += diff if self.volume < 0: self.volume = 0 if self.volume > 100: self.volume = 100 - self.plugin_base.backend.set_input_volume( - input_name, self.volume_to_db(self.volume) - ) + self.plugin_base.backend.set_input_volume(input_name, self.volume_to_db(self.volume)) self.on_tick() def on_tick(self): @@ -249,17 +205,17 @@ def reconnect_obs(self): self.load_configs() self.muted = None self.volume = None - + def volume_to_db(self, vol): if vol == 0: return -100 if vol > 100: return 0 - return math.log(vol / 100) * 10 / math.log(1.5) + return math.log(vol/100)*10/math.log(1.5) def db_to_volume(self, db): if db < -100: return 0 if db > 0: return 100 - return math.floor(1.5 ** (db / 10) * 100) + return math.floor(1.5**(db/10) * 100) \ No newline at end of file diff --git a/actions/InputMute/InputMuteBase.py b/actions/InputMute/InputMuteBase.py index f620054..3ff1074 100644 --- a/actions/InputMute/InputMuteBase.py +++ b/actions/InputMute/InputMuteBase.py @@ -29,12 +29,8 @@ def __init__(self, *args, **kwargs): self.image_path_map = { State.UNKNOWN: os.path.join(self.plugin_base.PATH, "assets", "error.png"), - State.ENABLED: os.path.join( - self.plugin_base.PATH, "assets", "input_unmuted.png" - ), - State.DISABLED: os.path.join( - self.plugin_base.PATH, "assets", "input_muted.png" - ), + State.ENABLED: os.path.join(self.plugin_base.PATH, "assets", "input_unmuted.png"), + State.DISABLED: os.path.join(self.plugin_base.PATH, "assets", "input_muted.png"), } @property @@ -56,15 +52,11 @@ def on_ready(self): # Show current input mute status threading.Thread( - target=self.show_current_input_mute_status, - daemon=True, - name="show_current_input_mute_status", + target=self.show_current_input_mute_status, daemon=True, name="show_current_input_mute_status" ).start() def set_media(self, *args, **kwargs): - super().set_media( - media_path=self.image_path_map.get(self.current_state), *args, **kwargs - ) + super().set_media(media_path=self.image_path_map.get(self.current_state), *args, **kwargs) def show_current_input_mute_status(self): if not self.plugin_base.get_connected(): @@ -105,8 +97,7 @@ def get_config_rows(self) -> list: self.input_model = Gtk.StringList() self.input_row = Adw.ComboRow( - model=self.input_model, - title=self.plugin_base.lm.get("actions.toggle-input-mute-row.label"), + model=self.input_model, title=self.plugin_base.lm.get("actions.toggle-input-mute-row.label") ) self.connect_signals() @@ -136,11 +127,7 @@ def load_input_model(self): if self.plugin_base.backend.get_connected(): inputs = self.plugin_base.backend.get_inputs() if inputs is None: - self.set_media( - media_path=os.path.join( - self.plugin_base.PATH, "assets", "error.png" - ) - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return for input in inputs: self.input_model.append(input) @@ -179,14 +166,10 @@ def on_key_down(self): except NotConnectedError: self.current_state = State.UNKNOWN self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return except InputNotFoundError: - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return next_state = self.next_state() diff --git a/actions/RecPlayPause/RecPlayPause.py b/actions/RecPlayPause/RecPlayPause.py index 42c080f..4073a27 100644 --- a/actions/RecPlayPause/RecPlayPause.py +++ b/actions/RecPlayPause/RecPlayPause.py @@ -5,7 +5,6 @@ from src.backend.PluginManager.PluginBase import PluginBase import os - class RecPlayPause(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -20,13 +19,9 @@ def on_ready(self): self.reconnect_obs() # Show current rec status - threading.Thread( - target=self.show_current_rec_status, - daemon=True, - name="show_current_rec_status", - ).start() + threading.Thread(target=self.show_current_rec_status, daemon=True, name="show_current_rec_status").start() - def show_current_rec_status(self, new_paused=False): + def show_current_rec_status(self, new_paused = False): if not self.plugin_base.get_connected(): self.show_error() return @@ -70,4 +65,4 @@ def on_key_down(self): self.plugin_base.backend.toggle_record_pause() def on_tick(self): - self.show_current_rec_status() + self.show_current_rec_status() \ No newline at end of file diff --git a/actions/SaveReplayBuffer/SaveReplayBuffer.py b/actions/SaveReplayBuffer/SaveReplayBuffer.py index 9c9d8a9..b4744eb 100644 --- a/actions/SaveReplayBuffer/SaveReplayBuffer.py +++ b/actions/SaveReplayBuffer/SaveReplayBuffer.py @@ -6,7 +6,6 @@ from src.backend.PluginManager.PluginBase import PluginBase import os - # from ...OBSActionBase import OBSActionBase import threading from plugins.com_core447_OBSPlugin.OBSActionBase import OBSActionBase @@ -15,8 +14,6 @@ from src.backend.PluginManager.PluginBase import PluginBase import os - - class SaveReplayBuffer(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -24,16 +21,9 @@ def __init__(self, *args, **kwargs): def on_ready(self): # Connect to obs if not connected if self.plugin_base.backend is not None: - if ( - not self.plugin_base.get_connected() - ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() - self.set_media( - media_path=os.path.join( - self.plugin_base.PATH, "assets", "replay_buffer_save.png" - ), - size=0.85, - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "replay_buffer_save.png"), size=0.85) def on_key_down(self): if self.plugin_base.backend is None: @@ -42,4 +32,4 @@ def on_key_down(self): if not self.plugin_base.backend.get_connected(): self.show_error() return - self.plugin_base.backend.save_replay_buffer() + self.plugin_base.backend.save_replay_buffer() \ No newline at end of file diff --git a/actions/SceneItem/SceneItem.py b/actions/SceneItem/SceneItem.py index dacdff6..6ec4e60 100644 --- a/actions/SceneItem/SceneItem.py +++ b/actions/SceneItem/SceneItem.py @@ -11,7 +11,6 @@ # Import gtk modules import gi - gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Gtk, Adw @@ -24,12 +23,8 @@ def __init__(self, *args, **kwargs): self.image_path_map = { State.UNKNOWN: os.path.join(self.plugin_base.PATH, "assets", "error.png"), - State.ENABLED: os.path.join( - self.plugin_base.PATH, "assets", "scene_item_enabled.png" - ), - State.DISABLED: os.path.join( - self.plugin_base.PATH, "assets", "scene_item_disabled.png" - ), + State.ENABLED: os.path.join(self.plugin_base.PATH, "assets", "scene_item_enabled.png"), + State.DISABLED: os.path.join(self.plugin_base.PATH, "assets", "scene_item_disabled.png") } def on_ready(self): @@ -40,17 +35,11 @@ def on_ready(self): self.reconnect_obs() # Show current scene item status - threading.Thread( - target=self.show_current_scene_item_status, - daemon=True, - name="show_current_scene_item_status", - ).start() + threading.Thread(target=self.show_current_scene_item_status, daemon=True, name="show_current_scene_item_status").start() # Copy-paste count: 1 def set_media(self, *args, **kwargs): - super().set_media( - media_path=self.image_path_map.get(self.current_state), *args, **kwargs - ) + super().set_media(media_path=self.image_path_map.get(self.current_state), *args, **kwargs) def show_current_scene_item_status(self): if not self.plugin_base.get_connected(): @@ -64,9 +53,7 @@ def show_current_scene_item_status(self): self.set_media() return - status = self.plugin_base.backend.get_scene_item_enabled( - self.get_settings().get("scene"), self.get_settings().get("item") - ) + status = self.plugin_base.backend.get_scene_item_enabled(self.get_settings().get("scene"), self.get_settings().get("item")) if status is None: self.current_state = State.UNKNOWN self.show_error() @@ -89,18 +76,10 @@ def get_config_rows(self) -> list: super_rows = super().get_config_rows() self.scene_model = Gtk.StringList() - self.scene_row = Adw.ComboRow( - model=self.scene_model, - title=self.plugin_base.lm.get("actions.switch.scene-row.label"), - ) + self.scene_row = Adw.ComboRow(model=self.scene_model, title=self.plugin_base.lm.get("actions.switch.scene-row.label")) self.item_model = Gtk.StringList() - self.item_row = Adw.ComboRow( - model=self.item_model, - title=self.plugin_base.lm.get( - "actions.toggle-scene-item-enabled-row.label" - ), - ) + self.item_row = Adw.ComboRow(model=self.item_model, title=self.plugin_base.lm.get("actions.toggle-scene-item-enabled-row.label")) self.connect_signals() @@ -153,11 +132,7 @@ def load_items_for_scene(self, scene_name): if self.plugin_base.backend.get_connected(): items = self.plugin_base.backend.get_scene_items(scene_name) if items is None: - self.set_media( - media_path=os.path.join( - self.plugin_base.PATH, "assets", "error.png" - ) - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return for item in items: self.item_model.append(item) @@ -219,9 +194,7 @@ def on_key_down(self): return next_bool = bool(self.next_state().value) - self.plugin_base.backend.set_scene_item_enabled( - scene_name, item_name, next_bool - ) + self.plugin_base.backend.set_scene_item_enabled(scene_name, item_name, next_bool) self.on_tick() def on_tick(self): diff --git a/actions/SwitchScene/SwitchScene.py b/actions/SwitchScene/SwitchScene.py index 3955e53..302fe8b 100644 --- a/actions/SwitchScene/SwitchScene.py +++ b/actions/SwitchScene/SwitchScene.py @@ -8,22 +8,18 @@ # Import gtk modules import gi - gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Gtk, Adw - class SwitchScene(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - + def on_ready(self): # Connect to obs if not connected if self.plugin_base.backend is not None: - if ( - not self.plugin_base.get_connected() - ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() media_path = os.path.join(self.plugin_base.PATH, "assets", "scene.png") @@ -33,10 +29,7 @@ def get_config_rows(self) -> list: super_rows = super().get_config_rows() self.scene_model = Gtk.StringList() - self.scene_row = Adw.ComboRow( - model=self.scene_model, - title=self.plugin_base.lm.get("actions.switch.scene-row.label"), - ) + self.scene_row = Adw.ComboRow(model=self.scene_model, title=self.plugin_base.lm.get("actions.switch.scene-row.label")) self.connect_signals() @@ -45,7 +38,7 @@ def get_config_rows(self) -> list: super_rows.append(self.scene_row) return super_rows - + def connect_signals(self): self.scene_row.connect("notify::selected", self.on_change_scene) @@ -82,7 +75,7 @@ def load_selected_device(self): self.scene_row.set_selected(i) self.connect_signals() return - + self.scene_row.set_selected(Gtk.INVALID_LIST_POSITION) self.connect_signals() @@ -102,4 +95,4 @@ def reconnect_obs(self): super().reconnect_obs() if hasattr(self, "scene_model"): self.load_scene_model() - self.load_configs() + self.load_configs() \ No newline at end of file diff --git a/actions/SwitchSceneCollection/SwitchSceneCollection.py b/actions/SwitchSceneCollection/SwitchSceneCollection.py index 37531f3..b70d068 100644 --- a/actions/SwitchSceneCollection/SwitchSceneCollection.py +++ b/actions/SwitchSceneCollection/SwitchSceneCollection.py @@ -8,37 +8,27 @@ # Import gtk modules import gi - gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") from gi.repository import Gtk, Adw - class SwitchSceneCollection(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - + def on_ready(self): # Connect to obs if not connected if self.plugin_base.backend is not None: - if ( - not self.plugin_base.get_connected() - ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "scene.png"), - size=0.75, - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "scene.png"), size=0.75) def get_config_rows(self) -> list: super_rows = super().get_config_rows() self.scene_collection_model = Gtk.StringList() - self.scene_collection_row = Adw.ComboRow( - model=self.scene_collection_model, - title=self.plugin_base.lm.get("actions.switch-scene-collection-row.label"), - ) + self.scene_collection_row = Adw.ComboRow(model=self.scene_collection_model, title=self.plugin_base.lm.get("actions.switch-scene-collection-row.label")) self.connect_signals() @@ -47,17 +37,13 @@ def get_config_rows(self) -> list: super_rows.append(self.scene_collection_row) return super_rows - + def connect_signals(self): - self.scene_collection_row.connect( - "notify::selected", self.on_change_scene_collection - ) + self.scene_collection_row.connect("notify::selected", self.on_change_scene_collection) def disconnect_signals(self): try: - self.scene_collection_row.disconnect_by_func( - self.on_change_scene_collection - ) + self.scene_collection_row.disconnect_by_func(self.on_change_scene_collection) except TypeError as e: pass @@ -88,16 +74,14 @@ def load_selected_device(self): self.scene_collection_row.set_selected(i) self.connect_signals() return - + self.scene_collection_row.set_selected(Gtk.INVALID_LIST_POSITION) self.connect_signals() def on_change_scene_collection(self, *args): settings = self.get_settings() selected_index = self.scene_collection_row.get_selected() - settings["scene_collection"] = self.scene_collection_model[ - selected_index - ].get_string() + settings["scene_collection"] = self.scene_collection_model[selected_index].get_string() self.set_settings(settings) def on_key_down(self): @@ -110,4 +94,4 @@ def reconnect_obs(self): super().reconnect_obs() if hasattr(self, "scene_collection_model"): self.load_scene_collection_model() - self.load_configs() + self.load_configs() \ No newline at end of file diff --git a/actions/ToggleRecord/ToggleRecord.py b/actions/ToggleRecord/ToggleRecord.py index 74e7c1b..865d7ec 100644 --- a/actions/ToggleRecord/ToggleRecord.py +++ b/actions/ToggleRecord/ToggleRecord.py @@ -6,8 +6,6 @@ from src.backend.PluginManager.PluginBase import PluginBase import os - - class ToggleRecord(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -17,19 +15,13 @@ def on_ready(self): self.current_state = -1 # Connect to obs if not connected if self.plugin_base.backend is not None: - if ( - not self.plugin_base.get_connected() - ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() # Show current rec status - threading.Thread( - target=self.show_current_rec_status, - daemon=True, - name="show_current_rec_status", - ).start() + threading.Thread(target=self.show_current_rec_status, daemon=True, name="show_current_rec_status").start() - def show_current_rec_status(self, new_paused=False): + def show_current_rec_status(self, new_paused = False): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() @@ -62,7 +54,7 @@ def show_for_state(self, state: int): if state == self.current_state: return - + self.current_state = state image = "record_inactive.png" if state == 0: @@ -92,17 +84,13 @@ def on_tick(self): def show_rec_time(self): if not self.plugin_base.backend.get_connected(): - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return status = self.plugin_base.backend.get_record_status() if status is None: - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if not status["active"]: self.set_bottom_label(None) return - self.set_bottom_label(status["timecode"][:-4], font_size=16) + self.set_bottom_label(status["timecode"][:-4], font_size=16) \ No newline at end of file diff --git a/actions/ToggleReplayBuffer/ToggleReplayBuffer.py b/actions/ToggleReplayBuffer/ToggleReplayBuffer.py index 0895284..a5550d3 100644 --- a/actions/ToggleReplayBuffer/ToggleReplayBuffer.py +++ b/actions/ToggleReplayBuffer/ToggleReplayBuffer.py @@ -6,8 +6,6 @@ from src.backend.PluginManager.PluginBase import PluginBase import os - - class ToggleReplayBuffer(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -17,40 +15,28 @@ def on_ready(self): self.current_state = -1 # Connect to obs if not connected if self.plugin_base.backend is not None: - if ( - not self.plugin_base.get_connected() - ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() # Show current replay buffer status - threading.Thread( - target=self.show_current_replay_buffer_status, - daemon=True, - name="show_current_replay_buffer_status", - ).start() + threading.Thread(target=self.show_current_replay_buffer_status, daemon=True, name="show_current_replay_buffer_status").start() - def show_current_replay_buffer_status(self, new_paused=False): + def show_current_replay_buffer_status(self, new_paused = False): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if not self.plugin_base.backend.get_connected(): self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return status = self.plugin_base.backend.get_replay_buffer_status() if status is None: self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if status["active"]: self.show_for_state(1) @@ -64,7 +50,7 @@ def show_for_state(self, state: int): """ if state == self.current_state: return - + self.current_state = state image = "replay_buffer_disabled.png" if state == 0: @@ -78,16 +64,12 @@ def on_key_down(self): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if not self.plugin_base.backend.get_connected(): self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if self.current_state == 0: self.plugin_base.backend.start_replay_buffer() @@ -96,4 +78,4 @@ def on_key_down(self): self.on_tick() def on_tick(self): - self.show_current_replay_buffer_status() + self.show_current_replay_buffer_status() \ No newline at end of file diff --git a/actions/ToggleStream/ToggleStream.py b/actions/ToggleStream/ToggleStream.py index 7271b9d..897391d 100644 --- a/actions/ToggleStream/ToggleStream.py +++ b/actions/ToggleStream/ToggleStream.py @@ -6,26 +6,20 @@ from src.backend.PluginManager.PluginBase import PluginBase import os - - class ToggleStream(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.current_state = -1 - + def on_ready(self): self.current_state = -1 if self.plugin_base.backend is None: if not self.plugin_base.get_connected(): self.reconnect_obs() - - threading.Thread( - target=self.show_current_stream_status, - daemon=True, - name="show_current_stream_status", - ).start() - - def show_current_stream_status(self, new_paused=False): + + threading.Thread(target=self.show_current_stream_status, daemon=True, name="show_current_stream_status").start() + + def show_current_stream_status(self, new_paused = False): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() @@ -47,7 +41,7 @@ def show_current_stream_status(self, new_paused=False): self.show_for_state(1) else: self.show_for_state(0) - + def show_for_state(self, state: int): """ 0: Not Streaming @@ -56,10 +50,10 @@ def show_for_state(self, state: int): """ if state in [1, 2]: self.show_stream_time() - + if state == self.current_state: return - + self.current_state = state image = "stream_inactive.png" if state == 0: @@ -68,9 +62,9 @@ def show_for_state(self, state: int): image = "stream_active.png" elif state == 2: image = "stream_reconnecting.png" - + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", image)) - + def on_key_down(self): if self.plugin_base.backend is None: self.current_state = -1 @@ -82,24 +76,20 @@ def on_key_down(self): return self.plugin_base.backend.toggle_stream() self.on_tick() - + def on_tick(self): self.show_current_stream_status() - + def show_stream_time(self): if not self.plugin_base.backend.get_connected(): - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return status = self.plugin_base.backend.get_stream_status() if status is None: - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return - + if not status["active"]: self.set_bottom_label(None) return - self.set_bottom_label(status["timecode"][:-4]) + self.set_bottom_label(status["timecode"][:-4]) \ No newline at end of file diff --git a/actions/ToggleStudioMode/ToggleStudioMode.py b/actions/ToggleStudioMode/ToggleStudioMode.py index 48cdf38..117c210 100644 --- a/actions/ToggleStudioMode/ToggleStudioMode.py +++ b/actions/ToggleStudioMode/ToggleStudioMode.py @@ -6,8 +6,6 @@ from src.backend.PluginManager.PluginBase import PluginBase import os - - class ToggleStudioMode(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -17,40 +15,28 @@ def on_ready(self): self.current_state = -1 # Connect to obs if not connected if self.plugin_base.backend is not None: - if ( - not self.plugin_base.get_connected() - ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() # Show current studio mode status - threading.Thread( - target=self.show_current_studio_mode_status, - daemon=True, - name="show_current_studio_mode_status", - ).start() + threading.Thread(target=self.show_current_studio_mode_status, daemon=True, name="show_current_studio_mode_status").start() - def show_current_studio_mode_status(self, new_paused=False): + def show_current_studio_mode_status(self, new_paused = False): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if not self.plugin_base.backend.get_connected(): self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return status = self.plugin_base.backend.get_studio_mode_enabled() if status is None: self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if status["active"]: self.show_for_state(1) @@ -64,7 +50,7 @@ def show_for_state(self, state: int): """ if state == self.current_state: return - + self.current_state = state image = "studio_mode_disabled.png" if state == 0: @@ -78,16 +64,12 @@ def on_key_down(self): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if not self.plugin_base.backend.get_connected(): self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if self.current_state == 0: self.plugin_base.backend.set_studio_mode_enabled(True) @@ -96,4 +78,4 @@ def on_key_down(self): self.on_tick() def on_tick(self): - self.show_current_studio_mode_status() + self.show_current_studio_mode_status() \ No newline at end of file diff --git a/actions/ToggleVirtualCamera/ToggleVirtualCamera.py b/actions/ToggleVirtualCamera/ToggleVirtualCamera.py index afb850d..400e11f 100644 --- a/actions/ToggleVirtualCamera/ToggleVirtualCamera.py +++ b/actions/ToggleVirtualCamera/ToggleVirtualCamera.py @@ -6,8 +6,6 @@ from src.backend.PluginManager.PluginBase import PluginBase import os - - class ToggleVirtualCamera(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -17,40 +15,28 @@ def on_ready(self): self.current_state = -1 # Connect to obs if not connected if self.plugin_base.backend is not None: - if ( - not self.plugin_base.get_connected() - ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() # Show current virtual camera status - threading.Thread( - target=self.show_current_virtual_camera_status, - daemon=True, - name="show_current_virtual_camera_status", - ).start() + threading.Thread(target=self.show_current_virtual_camera_status, daemon=True, name="show_current_virtual_camera_status").start() - def show_current_virtual_camera_status(self, new_paused=False): + def show_current_virtual_camera_status(self, new_paused = False): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if not self.plugin_base.backend.get_connected(): self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return status = self.plugin_base.backend.get_virtual_camera_status() if status is None: self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if status["active"]: self.show_for_state(1) @@ -64,7 +50,7 @@ def show_for_state(self, state: int): """ if state == self.current_state: return - + self.current_state = state image = "virtual_camera_disabled.png" if state == 0: @@ -72,24 +58,18 @@ def show_for_state(self, state: int): elif state == 1: image = "virtual_camera_enabled.png" - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", image), size=0.75 - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", image), size=0.75) def on_key_down(self): if self.plugin_base.backend is None: self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if not self.plugin_base.backend.get_connected(): self.current_state = -1 self.show_error() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png") - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "error.png")) return if self.current_state == 0: self.plugin_base.backend.start_virtual_camera() @@ -98,4 +78,4 @@ def on_key_down(self): self.on_tick() def on_tick(self): - self.show_current_virtual_camera_status() + self.show_current_virtual_camera_status() \ No newline at end of file diff --git a/actions/TriggerTransition/TriggerTransition.py b/actions/TriggerTransition/TriggerTransition.py index bdbde98..6a9fe8c 100644 --- a/actions/TriggerTransition/TriggerTransition.py +++ b/actions/TriggerTransition/TriggerTransition.py @@ -6,8 +6,6 @@ from src.backend.PluginManager.PluginBase import PluginBase import os - - class TriggerTransition(OBSActionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -15,14 +13,9 @@ def __init__(self, *args, **kwargs): def on_ready(self): # Connect to obs if not connected if self.plugin_base.backend is not None: - if ( - not self.plugin_base.get_connected() - ): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) + if not self.plugin_base.get_connected(): # self.plugin_base.obs.connect_to(host="localhost", port=4444, timeout=3, legacy=False) self.reconnect_obs() - self.set_media( - media_path=os.path.join(self.plugin_base.PATH, "assets", "transition.png"), - size=0.85, - ) + self.set_media(media_path=os.path.join(self.plugin_base.PATH, "assets", "transition.png"), size=0.85) def on_key_down(self): if self.plugin_base.backend is None: @@ -31,4 +24,4 @@ def on_key_down(self): if not self.plugin_base.backend.get_connected(): self.show_error() return - self.plugin_base.backend.trigger_transition() + self.plugin_base.backend.trigger_transition() \ No newline at end of file diff --git a/actions/mixins/MixinBase.py b/actions/mixins/MixinBase.py index d31202c..43ac50b 100644 --- a/actions/mixins/MixinBase.py +++ b/actions/mixins/MixinBase.py @@ -28,9 +28,7 @@ def current_state(self) -> State: @current_state.setter def current_state(self, val: int | State): if not val in State: - log.warning( - f"current_state setter called with non-State type {type(val)=} {val=}." - ) + log.warning(f"current_state setter called with non-State type {type(val)=} {val=}.") val = State(val) self._current_state = val diff --git a/actions/mixins/SetMixin.py b/actions/mixins/SetMixin.py index 7e2a9ea..36956dd 100644 --- a/actions/mixins/SetMixin.py +++ b/actions/mixins/SetMixin.py @@ -17,16 +17,11 @@ def __init__(self, set_mixin: "SetMixin"): self.input_model = Gtk.StringList() self.input_row = Adw.ComboRow( - model=self.input_model, - title=set_mixin.plugin_base.lm.get("actions.mixins.set.label"), + model=self.input_model, title=set_mixin.plugin_base.lm.get("actions.mixins.set.label") ) - self.input_model.append( - set_mixin.plugin_base.lm.get("actions.mixins.set.enable") - ) - self.input_model.append( - set_mixin.plugin_base.lm.get("actions.mixins.set.disable") - ) + self.input_model.append(set_mixin.plugin_base.lm.get("actions.mixins.set.enable")) + self.input_model.append(set_mixin.plugin_base.lm.get("actions.mixins.set.disable")) self.input_row.connect("notify::selected", self.on_select) diff --git a/backend/OBSController.py b/backend/OBSController.py index 8c10cc0..2dea994 100644 --- a/backend/OBSController.py +++ b/backend/OBSController.py @@ -5,13 +5,10 @@ import socket import ipaddress - class OBSController(obsws): def __init__(self): self.connected = False - self.event_obs: obsws = ( - None # All events are connected to this to avoid crash if a request is made in an event - ) + self.event_obs: obsws = None # All events are connected to this to avoid crash if a request is made in an event pass def validate_dns(self, host: str) -> bool: @@ -33,7 +30,7 @@ def validate_dns(self, host: str) -> bool: return True # Split into labels and validate each - labels = host.split(".") + labels = host.split('.') if not labels: return False @@ -52,7 +49,7 @@ def validate_dns(self, host: str) -> bool: return False # Middle characters can be alphanumeric or hyphen for char in label: - if not (char.isalnum() or char == "-"): + if not (char.isalnum() or char == '-'): return False return True @@ -69,7 +66,7 @@ def validate_ip(self, host: str): host = host.strip() # Handle bracket-wrapped IPv6 addresses [::1] - if host.startswith("[") and host.endswith("]"): + if host.startswith('[') and host.endswith(']'): host = host[1:-1] # Try to parse as IP address (IPv4 or IPv6) @@ -95,11 +92,7 @@ def register(self, *args, **kwargs): """ try: self.event_obs.register(*args, **kwargs) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def connect_to(self, host=None, port=None, timeout=1, legacy=False, **kwargs): @@ -119,7 +112,7 @@ def connect_to(self, host=None, port=None, timeout=1, legacy=False, **kwargs): addr = ipaddress.ip_address(host) if isinstance(addr, ipaddress.IPv6Address): # Only wrap if not already wrapped - if not (host.startswith("[") and host.endswith("]")): + if not (host.startswith('[') and host.endswith(']')): connection_host = f"[{host}]" log.debug(f"Wrapped IPv6 address: {host} -> {connection_host}") except ValueError: @@ -128,54 +121,16 @@ def connect_to(self, host=None, port=None, timeout=1, legacy=False, **kwargs): try: log.debug(f"Trying to connect to obs with legacy: {legacy}") - super().__init__( - host=connection_host, - port=port, - timeout=timeout, - legacy=legacy, - on_connect=self.on_connect, - on_disconnect=self.on_disconnect, - authreconnect=5, - **kwargs, - ) - self.event_obs = obsws( - host=connection_host, - port=port, - timeout=timeout, - legacy=legacy, - on_connect=self.on_connect, - on_disconnect=self.on_disconnect, - authreconnect=5, - **kwargs, - ) + super().__init__(host=connection_host, port=port, timeout=timeout, legacy=legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) + self.event_obs = obsws(host=connection_host, port=port, timeout=timeout, legacy=legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) self.connect() log.info("Successfully connected to OBS") return True except (obswebsocket.exceptions.ConnectionFailure, ValueError) as e: try: - log.error( - f"Failed to connect to OBS with legacy: {legacy}, trying with legacy: {not legacy}" - ) - super().__init__( - host=connection_host, - port=port, - timeout=timeout, - legacy=not legacy, - on_connect=self.on_connect, - on_disconnect=self.on_disconnect, - authreconnect=5, - **kwargs, - ) - self.event_obs = obsws( - host=connection_host, - port=port, - timeout=timeout, - legacy=not legacy, - on_connect=self.on_connect, - on_disconnect=self.on_disconnect, - authreconnect=5, - **kwargs, - ) + log.error(f"Failed to connect to OBS with legacy: {legacy}, trying with legacy: {not legacy}") + super().__init__(host=connection_host, port=port, timeout=timeout, legacy=not legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) + self.event_obs = obsws(host=connection_host, port=port, timeout=timeout, legacy=not legacy, on_connect=self.on_connect, on_disconnect=self.on_disconnect, authreconnect=5, **kwargs) self.connect() log.info("Successfully connected to OBS") @@ -183,25 +138,18 @@ def connect_to(self, host=None, port=None, timeout=1, legacy=False, **kwargs): except (obswebsocket.exceptions.ConnectionFailure, ValueError) as e: log.error(f"Failed to connect to OBS: {e}") + ## Streaming def start_stream(self) -> None: try: self.call(requests.StartStream()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def stop_stream(self) -> None: try: self.call(requests.StopStream()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def toggle_stream(self): @@ -210,11 +158,7 @@ def toggle_stream(self): """ try: self.call(requests.ToggleStream()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def get_stream_status(self) -> bool: @@ -230,52 +174,33 @@ def get_stream_status(self) -> bool: """ try: return self.call(requests.GetStreamStatus()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) - def send_stream_caption(self, caption: str): + def send_stream_caption(self, caption:str): try: self.call(requests.SendStreamCaption(caption=caption)) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) + ## Recording def start_record(self) -> None: try: return self.call(requests.StartRecord()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def pause_record(self): try: return self.call(requests.PauseRecord()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def resume_record(self): try: return self.call(requests.ResumeRecord()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def stop_recording(self) -> None: @@ -284,11 +209,7 @@ def stop_recording(self) -> None: """ try: return self.call(requests.StopRecord()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def get_record_status(self): @@ -301,33 +222,22 @@ def get_record_status(self): """ try: return self.call(requests.GetRecordStatus()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def toggle_record(self): try: return self.call(requests.ToggleRecord()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def toggle_record_pause(self): try: return self.call(requests.ToggleRecordPause()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) + ## Replay Buffer def get_replay_buffer_status(self): """ @@ -341,43 +251,28 @@ def get_replay_buffer_status(self): return else: return request - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def start_replay_buffer(self): try: return self.call(requests.StartReplayBuffer()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def stop_replay_buffer(self): try: return self.call(requests.StopReplayBuffer()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def save_replay_buffer(self): try: return self.call(requests.SaveReplayBuffer()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) + ## Virtual Camera def get_virtual_camera_status(self): """ @@ -391,31 +286,19 @@ def get_virtual_camera_status(self): return else: return request - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def start_virtual_camera(self): try: return self.call(requests.StartVirtualCam()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def stop_virtual_camera(self): try: return self.call(requests.StopVirtualCam()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) ## Studio Mode @@ -425,43 +308,28 @@ def get_studio_mode_enabled(self): """ try: return self.call(requests.GetStudioModeEnabled()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) - def set_studio_mode_enabled(self, enabled: bool): + def set_studio_mode_enabled(self, enabled:bool): try: return self.call(requests.SetStudioModeEnabled(studioModeEnabled=enabled)) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def trigger_transition(self): try: return self.call(requests.TriggerStudioModeTransition()) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) + ## Input mixer def get_inputs(self) -> list: try: inputs = self.call(requests.GetInputList()).getInputs() return [input["inputName"] for input in inputs] - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def get_input_muted(self, input: str) -> None: @@ -476,21 +344,13 @@ def get_input_muted(self, input: str) -> None: return else: return request - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def set_input_muted(self, input: str, muted: bool) -> None: try: self.call(requests.SetInputMute(inputName=input, inputMuted=muted)) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def get_input_volume(self, input: str): @@ -502,35 +362,22 @@ def get_input_volume(self, input: str): return else: return request - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def set_input_volume(self, input: str, volume: int) -> None: try: self.call(requests.SetInputVolume(inputName=input, inputVolumeDb=volume)) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) + ## Scene Items def get_scene_items(self, sceneName: str) -> list: try: - sceneItems = self.call( - requests.GetSceneItemList(sceneName=sceneName) - ).getSceneItems() + sceneItems = self.call(requests.GetSceneItemList(sceneName=sceneName)).getSceneItems() return [sceneItem["sourceName"] for sceneItem in sceneItems] - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def get_scene_item_enabled(self, sceneName: str, sourceName: str) -> None: @@ -538,145 +385,74 @@ def get_scene_item_enabled(self, sceneName: str, sourceName: str) -> None: sceneItemEnabled: bool -> Whether the scene item is enabled. true for enabled, false for disabled """ try: - sceneItemId = self.call( - requests.GetSceneItemId(sceneName=sceneName, sourceName=sourceName) - ).getSceneItemId() - return self.call( - requests.GetSceneItemEnabled( - sceneName=sceneName, sceneItemId=sceneItemId - ) - ) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + sceneItemId = self.call(requests.GetSceneItemId(sceneName=sceneName, sourceName=sourceName)).getSceneItemId() + return self.call(requests.GetSceneItemEnabled(sceneName=sceneName, sceneItemId=sceneItemId)) + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: if str(e) == "'sceneItemId'": log.warning("Cannot find the scene item!") else: log.error(e) - def set_scene_item_enabled( - self, sceneName: str, sourceName: str, enabled: bool - ) -> None: - try: - sceneItemId = self.call( - requests.GetSceneItemId(sceneName=sceneName, sourceName=sourceName) - ).getSceneItemId() - self.call( - requests.SetSceneItemEnabled( - sceneName=sceneName, - sceneItemId=sceneItemId, - sceneItemEnabled=enabled, - ) - ) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + def set_scene_item_enabled(self, sceneName: str, sourceName: str, enabled: bool) -> None: + try: + sceneItemId = self.call(requests.GetSceneItemId(sceneName=sceneName, sourceName=sourceName)).getSceneItemId() + self.call(requests.SetSceneItemEnabled(sceneName=sceneName, sceneItemId=sceneItemId, sceneItemEnabled=enabled)) + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) + ## Scenes def get_scenes(self) -> list: try: scenes = self.call(requests.GetSceneList()).getScenes() return [scene["sceneName"] for scene in scenes] - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) ## Credit for Studio Mode Preview fix: Rinma (https://github.com/Rinma) - def switch_to_scene(self, scene: str) -> None: + def switch_to_scene(self, scene:str) -> None: studioModeStatus = self.get_studio_mode_enabled() if studioModeStatus.datain["studioModeEnabled"]: try: self.call(requests.SetCurrentPreviewScene(sceneName=scene)) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) else: try: self.call(requests.SetCurrentProgramScene(sceneName=scene)) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) ## Scene Collections def get_scene_collections(self) -> list: try: - sceneCollections = self.call( - requests.GetSceneCollectionList() - ).getSceneCollections() + sceneCollections = self.call(requests.GetSceneCollectionList()).getSceneCollections() return sceneCollections - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def set_current_scene_collection(self, sceneCollectionName: str) -> None: try: - self.call( - requests.SetCurrentSceneCollection( - sceneCollectionName=sceneCollectionName - ) - ) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + self.call(requests.SetCurrentSceneCollection(sceneCollectionName=sceneCollectionName)) + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def get_source_filters(self, sourceName: str) -> list: try: - source_filters = self.call( - requests.GetSourceFilterList(sourceName=sourceName) - ).getfilters() + source_filters = self.call(requests.GetSourceFilterList(sourceName=sourceName)).getfilters() return source_filters - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) - def set_source_filter_enabled( - self, sourceName: str, filterName: str, enabled: bool - ) -> None: + def set_source_filter_enabled(self, sourceName: str, filterName: str, enabled: bool) -> None: try: - self.call( - requests.SetSourceFilterEnabled( - sourceName=sourceName, filterName=filterName, filterEnabled=enabled - ) - ) - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + self.call(requests.SetSourceFilterEnabled(sourceName=sourceName, filterName=filterName, filterEnabled=enabled)) + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) def get_source_filter(self, sourceName: str, filterName: str) -> None: try: - source_filter = self.call( - requests.GetSourceFilter(sourceName=sourceName, filterName=filterName) - ).datain + source_filter = self.call(requests.GetSourceFilter(sourceName=sourceName, filterName=filterName)).datain return source_filter - except ( - obswebsocket.exceptions.MessageTimeout, - websocket._exceptions.WebSocketConnectionClosedException, - KeyError, - ) as e: + except (obswebsocket.exceptions.MessageTimeout, websocket._exceptions.WebSocketConnectionClosedException, KeyError) as e: log.error(e) diff --git a/backend/backend.py b/backend/backend.py index 8205c56..e14eafc 100644 --- a/backend/backend.py +++ b/backend/backend.py @@ -1,5 +1,4 @@ import logging - LOG = logging.getLogger(__name__) # Set the logger level to ERROR LOG.setLevel(logging.ERROR) @@ -15,7 +14,6 @@ import os import threading - class Backend(BackendBase): def __init__(self): super().__init__() @@ -23,7 +21,7 @@ def __init__(self): self.OBSController.connect_to( host=self.frontend.get_settings().get("ip", "localhost"), port=self.frontend.get_settings().get("port", 4455), - password=self.frontend.get_settings().get("password") or "", + password=self.frontend.get_settings().get("password") or "" ) """ @@ -56,7 +54,7 @@ def get_stream_status(self) -> dict: "congestion": status.datain["outputCongestion"], "bytes": status.datain["outputBytes"], "skipped_frames": status.datain["outputSkippedFrames"], - "total_frames": status.datain["outputTotalFrames"], + "total_frames": status.datain["outputTotalFrames"] } def toggle_stream(self): @@ -64,7 +62,7 @@ def toggle_stream(self): if status is None: return False return status.datain["outputActive"] - + # Recording def get_record_status(self) -> dict: status = self.OBSController.get_record_status() @@ -75,7 +73,7 @@ def get_record_status(self) -> dict: "paused": status.datain["outputPaused"], "timecode": status.datain["outputTimecode"], "duration": status.datain["outputDuration"], - "bytes": status.datain["outputBytes"], + "bytes": status.datain["outputBytes"] } def toggle_record(self): @@ -89,7 +87,9 @@ def get_replay_buffer_status(self) -> dict: status = self.OBSController.get_replay_buffer_status() if status is None: return - return {"active": status.datain["outputActive"]} + return { + "active": status.datain["outputActive"] + } def start_replay_buffer(self): self.OBSController.start_replay_buffer() @@ -105,7 +105,9 @@ def get_virtual_camera_status(self) -> dict: status = self.OBSController.get_virtual_camera_status() if status is None: return - return {"active": status.datain["outputActive"]} + return { + "active": status.datain["outputActive"] + } def start_virtual_camera(self): self.OBSController.start_virtual_camera() @@ -118,7 +120,9 @@ def get_studio_mode_enabled(self) -> dict: status = self.OBSController.get_studio_mode_enabled() if status is None: return - return {"active": status.datain["studioModeEnabled"]} + return { + "active": status.datain["studioModeEnabled"] + } def set_studio_mode_enabled(self, enabled: bool): self.OBSController.set_studio_mode_enabled(enabled) @@ -134,7 +138,9 @@ def get_input_muted(self, input: str): status = self.OBSController.get_input_muted(input) if status is None: return - return {"muted": status.datain["inputMuted"]} + return { + "muted": status.datain["inputMuted"] + } def set_input_muted(self, input: str, muted: bool): self.OBSController.set_input_muted(input, muted) @@ -143,7 +149,9 @@ def get_input_volume(self, input: str): status = self.OBSController.get_input_volume(input) if status is None: return - return {"volume": status.datain["inputVolumeDb"]} + return { + "volume": status.datain["inputVolumeDb"] + } def set_input_volume(self, input: str, volume: int): self.OBSController.set_input_volume(input, volume) @@ -151,8 +159,8 @@ def set_input_volume(self, input: str, volume: int): # Scenes def get_scene_names(self) -> list[str]: return self.OBSController.get_scenes() - - def switch_to_scene(self, scene: str): + + def switch_to_scene(self, scene:str): self.OBSController.switch_to_scene(scene) # Scene Items @@ -163,7 +171,9 @@ def get_scene_item_enabled(self, sceneName: str, sourceName: str): status = self.OBSController.get_scene_item_enabled(sceneName, sourceName) if status is None: return - return {"enabled": status.datain["sceneItemEnabled"]} + return { + "enabled": status.datain["sceneItemEnabled"] + } def set_scene_item_enabled(self, sceneName: str, sourceName: str, enabled: bool): self.OBSController.set_scene_item_enabled(sceneName, sourceName, enabled) @@ -174,17 +184,14 @@ def get_scene_collections(self) -> list[str]: def set_current_scene_collection(self, sceneCollectionName: str): return self.OBSController.set_current_scene_collection(sceneCollectionName) - + def get_source_filters(self, sourceName: str) -> list: return self.OBSController.get_source_filters(sourceName) - - def set_source_filter_enabled( - self, sourceName: str, filterName: str, enabled: bool - ): + + def set_source_filter_enabled(self, sourceName: str, filterName: str, enabled: bool): self.OBSController.set_source_filter_enabled(sourceName, filterName, enabled) def get_source_filter(self, sourceName: str, filterName: str) -> None: return self.OBSController.get_source_filter(sourceName, filterName) - - -backend = Backend() + +backend = Backend() \ No newline at end of file