From 75e80e048446d7d94f4f048ed52ab0b39d4b6c7f Mon Sep 17 00:00:00 2001 From: Marc Seiler Date: Fri, 21 Aug 2026 08:46:43 -0400 Subject: [PATCH] fix: load Spotify actions in daemon mode --- __install__.py | 48 +++++++++++++++++ main.py | 136 ++++++++++++------------------------------------- 2 files changed, 81 insertions(+), 103 deletions(-) diff --git a/__install__.py b/__install__.py index 5a1a84f..2eb98c1 100644 --- a/__install__.py +++ b/__install__.py @@ -1,5 +1,53 @@ +import json +import os from streamcontroller_plugin_tools.installation_helpers import create_venv from os.path import join, abspath, dirname +LEGACY_ACTION_PREFIX = "dev_ReneLu_SpotifyControl::" +ACTION_PREFIX = "com_ReneLu_spotifyControl::" + + +def migrate_action_ids(): + pages_path = join(os.environ.get("XDG_DATA_HOME", os.path.expanduser("~/.local/share")), "pages") + if not os.path.isdir(pages_path): + return + + for directory, _, file_names in os.walk(pages_path): + for file_name in file_names: + if not file_name.endswith(".json"): + continue + + migrate_page(join(directory, file_name)) + + +def migrate_page(page_path): + try: + with open(page_path, "r", encoding="utf-8") as page_file: + page = json.load(page_file) + except (OSError, json.JSONDecodeError): + return + + changed = False + for input_type in ("keys", "dials", "touchscreens"): + for input_config in page.get(input_type, {}).values(): + for state in input_config.get("states", {}).values(): + for action in state.get("actions", []): + action_id = action.get("id") if isinstance(action, dict) else None + if isinstance(action_id, str) and action_id.startswith(LEGACY_ACTION_PREFIX): + action["id"] = ACTION_PREFIX + action_id.removeprefix(LEGACY_ACTION_PREFIX) + changed = True + + if changed: + temporary_path = f"{page_path}.spotify-control.tmp" + try: + with open(temporary_path, "w", encoding="utf-8") as page_file: + json.dump(page, page_file, indent=4) + os.replace(temporary_path, page_path) + except OSError: + if os.path.exists(temporary_path): + os.remove(temporary_path) + + toplevel = dirname(abspath(__file__)) +migrate_action_ids() create_venv(join(toplevel, "backend", ".venv"), join(toplevel, "backend", "requirements.txt")) diff --git a/main.py b/main.py index d119b41..7b71273 100755 --- a/main.py +++ b/main.py @@ -39,109 +39,39 @@ def __init__(self): self._settings_manager = PluginSettings(self) ## Register actions - self.shuffle_action_holder = ActionHolder( - plugin_base = self, - action_base = ShuffleAction, - action_id = "dev_ReneLu_SpotifyControl::ShuffleAction", - action_name = "Shuffle", - ) - self.add_action_holder(self.shuffle_action_holder) - - self.playpause_action_holder = ActionHolder( - plugin_base = self, - action_base = PlayPauseAction, - action_id = "dev_ReneLu_SpotifyControl::PlayPauseAction", - action_name = "Play / Pause", - ) - self.add_action_holder(self.playpause_action_holder) - - self.nexttrack_action_holder = ActionHolder( - plugin_base = self, - action_base = NextTrackAction, - action_id = "dev_ReneLu_SpotifyControl::NextTrackAction", - action_name = "Next Track", - ) - self.add_action_holder(self.nexttrack_action_holder) - - self.prevtrack_action_holder = ActionHolder( - plugin_base = self, - action_base = PrevTrackAction, - action_id = "dev_ReneLu_SpotifyControl::PrevTrackAction", - action_name = "Previous Track", - ) - self.add_action_holder(self.prevtrack_action_holder) - - self.vol_dwn_action_holder = ActionHolder( - plugin_base = self, - action_base = VolDwnAction, - action_id = "dev_ReneLu_SpotifyControl::VolDwnAction", - action_name = "Volume Down", - ) - self.add_action_holder(self.vol_dwn_action_holder) - - self.vol_up_action_holder = ActionHolder( - plugin_base = self, - action_base = VolUpAction, - action_id = "dev_ReneLu_SpotifyControl::VolUpAction", - action_name = "Volume Up", - ) - self.add_action_holder(self.vol_up_action_holder) - - self.vol_mute_action_holder = ActionHolder( - plugin_base = self, - action_base = VolMuteAction, - action_id = "dev_ReneLu_SpotifyControl::VolMuteAction", - action_name = "Volume Mute", - ) - self.add_action_holder(self.vol_mute_action_holder) - - self.repeat_action_holder = ActionHolder( - plugin_base = self, - action_base = RepeatAction, - action_id = "dev_ReneLu_SpotifyControl::RepeatAction", - action_name = "Repeat", - ) - self.add_action_holder(self.repeat_action_holder) - - self.vol_set_action_holder = ActionHolder( - plugin_base = self, - action_base = VolSetAction, - action_id = "dev_ReneLu_SpotifyControl::VolSetAction", - action_name = "Volume Set", - ) - self.add_action_holder(self.vol_set_action_holder) - - self.play_action_holder = ActionHolder( - plugin_base = self, - action_base = PlayAction, - action_id = "dev_ReneLu_SpotifyControl::PlayAction", - action_name = "Play", - ) - self.add_action_holder(self.play_action_holder) - - self.pause_action_holder = ActionHolder( - plugin_base = self, - action_base = PauseAction, - action_id = "dev_ReneLu_SpotifyControl::PauseAction", - action_name = "Pause", - ) - self.add_action_holder(self.pause_action_holder) - - self.info_action_holder = ActionHolder( - plugin_base = self, - action_base = InfoAction, - action_id = "dev_ReneLu_SpotifyControl::InfoAction", - action_name = "Info", - ) - self.add_action_holder(self.info_action_holder) - - self.element_play_action_holder = ActionHolder( - plugin_base = self, - action_base = ElementPlayAction, - action_id = "dev_ReneLu_SpotifyControl::ElementPlayAction", - action_name = "Element Play", - ) - self.add_action_holder(self.element_play_action_holder) + actions = [ + ("shuffle_action_holder", ShuffleAction, "ShuffleAction", "Shuffle"), + ("playpause_action_holder", PlayPauseAction, "PlayPauseAction", "Play / Pause"), + ("nexttrack_action_holder", NextTrackAction, "NextTrackAction", "Next Track"), + ("prevtrack_action_holder", PrevTrackAction, "PrevTrackAction", "Previous Track"), + ("vol_dwn_action_holder", VolDwnAction, "VolDwnAction", "Volume Down"), + ("vol_up_action_holder", VolUpAction, "VolUpAction", "Volume Up"), + ("vol_mute_action_holder", VolMuteAction, "VolMuteAction", "Volume Mute"), + ("repeat_action_holder", RepeatAction, "RepeatAction", "Repeat"), + ("vol_set_action_holder", VolSetAction, "VolSetAction", "Volume Set"), + ("play_action_holder", PlayAction, "PlayAction", "Play"), + ("pause_action_holder", PauseAction, "PauseAction", "Pause"), + ("info_action_holder", InfoAction, "InfoAction", "Info"), + ("element_play_action_holder", ElementPlayAction, "ElementPlayAction", "Element Play"), + ] + + for attribute, action, action_id_suffix, action_name in actions: + action_holder = ActionHolder( + plugin_base=self, + action_base=action, + action_id_suffix=action_id_suffix, + action_name=action_name, + ) + setattr(self, attribute, action_holder) + self.add_action_holder(action_holder) + + # Keep pages created before the plugin ID was corrected working. + self.add_action_holder(ActionHolder( + plugin_base=self, + action_base=action, + action_id=f"dev_ReneLu_SpotifyControl::{action_id_suffix}", + action_name=action_name, + )) # Register plugin self.register(