diff --git a/actions/SwitchScene/SwitchScene.py b/actions/SwitchScene/SwitchScene.py new file mode 100644 index 0000000..61be043 --- /dev/null +++ b/actions/SwitchScene/SwitchScene.py @@ -0,0 +1,99 @@ +from plugins.dev_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 +from GtkHelper.GtkHelper import ComboRow + +import os + +# 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, action_id: str, action_name: str, + deck_controller: "DeckController", page: Page, coords: str, plugin_base: PluginBase): + super().__init__(action_id=action_id, action_name=action_name, + deck_controller=deck_controller, page=page, coords=coords, plugin_base=plugin_base) + + def on_ready(self): + # Connect to obs if not connected + if not self.plugin_base.backend.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", "transition_slide.png") + self.set_media(media_path=media_path, 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.connect_signals() + + self.load_scene_model() + self.load_configs() + + super_rows.append(self.scene_row) + return super_rows + + def connect_signals(self): + self.scene_row.connect("notify::selected", self.on_change_scene) + + def disconnect_signals(self): + try: + self.scene_row.disconnect_by_func(self.on_change_scene) + except TypeError as e: + pass + + def load_scene_model(self): + self.disconnect_signals() + # Clear model + while self.scene_model.get_n_items() > 0: + self.scene_model.remove(0) + + # Load model + if self.plugin_base.backend.get_connected(): + scenes = self.plugin_base.backend.get_scene_names() + if scenes is None: + return + for scene in scenes: + self.scene_model.append(scene) + + self.connect_signals() + + def load_configs(self): + self.load_selected_device() + + def load_selected_device(self): + self.disconnect_signals() + settings = self.get_settings() + for i, scene_name in enumerate(self.scene_model): + if scene_name.get_string() == settings.get("scene"): + self.scene_row.set_selected(i) + self.connect_signals() + return + + self.scene_row.set_selected(Gtk.INVALID_LIST_POSITION) + self.connect_signals() + + def on_change_scene(self, *args): + settings = self.get_settings() + selected_index = self.scene_row.get_selected() + settings["scene"] = self.scene_model[selected_index].get_string() + self.set_settings(settings) + + def on_key_down(self): + scene_name = self.get_settings().get("scene") + if scene_name in [None, ""]: + return + self.plugin_base.backend.switch_to_scene(scene_name) + + 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 diff --git a/assets/transition_slide.png b/assets/transition_slide.png new file mode 100644 index 0000000..054d0b1 Binary files /dev/null and b/assets/transition_slide.png differ diff --git a/backend/backend.py b/backend/backend.py index c4f489e..8fc9c48 100644 --- a/backend/backend.py +++ b/backend/backend.py @@ -45,6 +45,18 @@ class Backend(BackendBase): def connect_to(self, *args, **kwargs): self.OBSController.connect_to(*args, **kwargs) + + def get_controller(self) -> OBSController: + """ + Calling methods on the returned controller will raise a circular reference error from Pyro + """ + return self.OBSController + + def get_scene_names(self) -> list[str]: + return self.OBSController.get_scenes() + + def switch_to_scene(self, scene:str): + self.OBSController.switch_to_scene(scene) print("init backend") backend = Backend() diff --git a/locales/en_US.json b/locales/en_US.json index 60dd084..372a40d 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -6,5 +6,7 @@ "actions.base.status.connected": "Successfully connected to OBS.", "actions.base.ip.label": "IP:", "actions.base.port.label": "Port:", - "actions.base.password.label": "Password:" + "actions.base.password.label": "Password:", + "actions.switch.scene-row.label": "Scene:", + "actions.switch-scene.name": "Switch Scene" } \ No newline at end of file diff --git a/main.py b/main.py index 9f01ab3..05c9641 100644 --- a/main.py +++ b/main.py @@ -21,6 +21,7 @@ from OBSActionBase import OBSActionBase from actions.ToggleRecord.ToggleRecord import ToggleRecord from actions.RecPlayPause.RecPlayPause import RecPlayPause +from actions.SwitchScene.SwitchScene import SwitchScene class OBS(PluginBase): def __init__(self): @@ -58,5 +59,13 @@ class OBS(PluginBase): ) self.add_action_holder(rec_play_pause_action_holder) + switch_scene_action_holder = ActionHolder( + plugin_base=self, + action_base=SwitchScene, + action_id="dev_core447_OBSPlugin::SwitchScene", + action_name=self.lm.get("actions.switch-scene.name") + ) + self.add_action_holder(switch_scene_action_holder) + # Load custom css self.add_css_stylesheet(os.path.join(self.PATH, "style.css")) \ No newline at end of file