diff --git a/actions/ToggleStream/ToggleStream.py b/actions/ToggleStream/ToggleStream.py new file mode 100644 index 0000000..4a7d6b1 --- /dev/null +++ b/actions/ToggleStream/ToggleStream.py @@ -0,0 +1,94 @@ +# from ...OBSActionbase import OBSActionBase +import threading +from plugins.com_core447_OBSPlugin.OBSActionBase import OBSActionBase +from src.backend.DeckManagement.DeckController import DeckController +from src.backend.PageManagement.Page import Page +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): + if self.plugin_base.backend is None: + self.current_state = -1 + self.show_error() + return + if not self.plugin_base.backend.get_connected(): + self.current_state = -1 + self.show_error() + return + status = self.plugin_base.backend.get_stream_status() + if status is None: + self.current_state = -1 + self.show_error() + return + if status["active"]: + if status["reconnecting"]: + self.show_for_state(2) + else: + self.show_for_state(1) + else: + self.show_for_state(0) + + def show_for_state(self, state: int): + """ + 0: Not Streaming + 1: Streaming Connected + 2: Streaming Reconnecting + """ + 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: + self.set_bottom_label(None) + elif state == 1: + 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 + self.show_error() + return + if not self.plugin_base.backend.get_connected(): + self.current_state = -1 + self.show_error() + 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")) + 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")) + return + + if not status["active"]: + self.set_bottom_label(None) + return + self.set_bottom_label(status["timecode"][:-4]) \ No newline at end of file diff --git a/assets/stream_active.png b/assets/stream_active.png new file mode 100644 index 0000000..9c9c702 Binary files /dev/null and b/assets/stream_active.png differ diff --git a/assets/stream_inactive.png b/assets/stream_inactive.png new file mode 100644 index 0000000..81b5ffe Binary files /dev/null and b/assets/stream_inactive.png differ diff --git a/assets/stream_reconnecting.png b/assets/stream_reconnecting.png new file mode 100644 index 0000000..9bd2d2c Binary files /dev/null and b/assets/stream_reconnecting.png differ diff --git a/backend/backend.py b/backend/backend.py index 4b0dd9b..ee96b16 100644 --- a/backend/backend.py +++ b/backend/backend.py @@ -31,9 +31,30 @@ class Backend(BackendBase): "duration": status.datain["outputDuration"], "bytes": status.datain["outputBytes"] } + + def get_stream_status(self) -> dict: + status = self.OBSController.get_stream_status() + if status is None: + return + return { + "active": status.datain["outputActive"], + "reconnecting": status.datain["outputReconnecting"], + "timecode": status.datain["outputTimecode"], + "duration": status.datain["outputDuration"], + "congestion": status.datain["outputCongestion"], + "bytes": status.datain["outputBytes"], + "skipped_frames": status.datain["outputSkippedFrames"], + "total_frames": status.datain["outputTotalFrames"] + } def get_connected(self) -> bool: return self.OBSController.connected + + def toggle_stream(self): + status = self.OBSController.toggle_stream() + if status is None: + return False + return status.datain["outputActive"] def toggle_record(self): self.OBSController.toggle_record() diff --git a/locales/de_DE.json b/locales/de_DE.json index e7233d9..a3e81ab 100644 --- a/locales/de_DE.json +++ b/locales/de_DE.json @@ -1,6 +1,7 @@ { "plugin.name": "OBS", "actions.toggle-record.name": "Aufnahme pausieren", + "actions.toggle-stream.name": "Streaming umschalten", "actions.rec-play-pause.name": "Play/Pause Aufnahme", "actions.base.status.no-connection": "Es konnte keine Verbindung zu OBS hergestellt werden.", "actions.base.ip.label": "IP:", diff --git a/locales/en_US.json b/locales/en_US.json index 372a40d..520c871 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -1,6 +1,7 @@ { "plugin.name": "OBS", "actions.toggle-record.name": "Toggle Recording", + "actions.toggle-stream.name": "Toggle Steaming", "actions.rec-play-pause.name": "Play/Pause Recording", "actions.base.status.no-connection": "Could not connect to OBS.", "actions.base.status.connected": "Successfully connected to OBS.", diff --git a/main.py b/main.py index 30f3503..2e3a7f1 100644 --- a/main.py +++ b/main.py @@ -20,6 +20,7 @@ sys.path.append(os.path.dirname(__file__)) from OBSActionBase import OBSActionBase from actions.ToggleRecord.ToggleRecord import ToggleRecord +from actions.ToggleStream.ToggleStream import ToggleStream from actions.RecPlayPause.RecPlayPause import RecPlayPause from actions.SwitchScene.SwitchScene import SwitchScene @@ -51,6 +52,14 @@ class OBS(PluginBase): ) self.add_action_holder(toggle_record_action_holder) + toggle_stream_action_holder = ActionHolder( + plugin_base=self, + action_base=ToggleStream, + action_id="com_core447_OBSPlugin::ToggleStream", + action_name=self.lm.get("actions.toggle-stream.name") + ) + self.add_action_holder(toggle_stream_action_holder) + rec_play_pause_action_holder = ActionHolder( plugin_base=self, action_base=RecPlayPause,