Skip to content

Commit fae5f0f

Browse files
committed
- added RepeatActiom
- UI now updates elements every second
1 parent 4152d01 commit fae5f0f

9 files changed

Lines changed: 280 additions & 30 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# Spotify Control for StreamController
22

3-
This WIP plugin allows you to control Spotify using StreamController.
3+
This WIP plugin allows you to control Spotify using StreamController. (Spotify Premium required)
44

55
It currently only provides actions for:
66

77
* play/pause/resume
88
* next song
99
* previous song
1010
* switch shuffle mode
11+
* switch repeat mode
1112
* adjust volume in 10% steps
1213
* show cover-art in play/resume button
1314

@@ -27,7 +28,6 @@ It currently only provides actions for:
2728

2829
## TODO:
2930

30-
- automatic refresh of icons based on spotify state
3131
- more functions
3232
- cleanup Code
3333

actions/MediaActions/PlayResumeAction.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def get_controller(self) -> SpotifyController:
3535

3636
def on_ready(self) -> None:
3737
self.update_state()
38+
self.get_controller.register_update_callback(self.update_state)
3839

3940
def on_key_down(self) -> None:
4041
print("Key down")
@@ -77,7 +78,7 @@ def merge_icon_on_background_centered(
7778
Returns:
7879
A new PIL Image object with the icon composited onto the background.
7980
"""
80-
if not background_img or not icon_img:
81+
if background_img is None or icon_img is None:
8182
raise ValueError("Both background and icon images must be provided.")
8283

8384
# Ensure images are in RGBA format to handle transparency properly
@@ -156,15 +157,16 @@ def load_background_media(self) -> Image.Image | None:
156157
except Exception as e:
157158
log.error(f"An unexpected error occurred while setting background: {e}")
158159

159-
160-
161-
def update_state(self):
162-
playing = self.get_controller.is_playing()
160+
def update_state(self, state=None):
161+
playing = self.get_controller.is_playing(state)
163162
icon_path = self.play_icon if not playing else self.pause_icon
164163
background = self.load_background_media()
165164
icon = self.load_overlay(icon_path)
166-
combined = self.merge_icon_on_background_centered(background, icon)
167-
self.set_media(image=combined.copy())
165+
if background and icon:
166+
combined = self.merge_icon_on_background_centered(background, icon)
167+
self.set_media(image=combined.copy())
168+
elif background is None and icon:
169+
self.set_media(image=icon)
168170

169171

170172

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Import StreamController modules
2+
from src.backend.PluginManager.ActionBase import ActionBase
3+
from src.backend.DeckManagement.DeckController import DeckController
4+
from src.backend.PageManagement.Page import Page
5+
from src.backend.PluginManager.PluginBase import PluginBase
6+
7+
# Import python modules
8+
import os
9+
from loguru import logger as log
10+
from GtkHelper.GenerativeUI.EntryRow import EntryRow # For regular text input
11+
from GtkHelper.GenerativeUI.PasswordEntryRow import PasswordEntryRow # For secrets
12+
13+
# Import gtk modules - used for the config rows
14+
import gi
15+
16+
from ...utils.SpotifyController import SpotifyController
17+
18+
gi.require_version("Gtk", "4.0")
19+
gi.require_version("Adw", "1")
20+
from gi.repository import Gtk, Adw
21+
22+
class Repeat(ActionBase):
23+
def __init__(self, *args, **kwargs):
24+
super().__init__(*args, **kwargs)
25+
self.repeat_context_icon = os.path.join(self.plugin_base.PATH, "assets", "repeat.png")
26+
self.repeat_one_icon = os.path.join(self.plugin_base.PATH, "assets", "repeat_one.png")
27+
self.no_repeat_icon = os.path.join(self.plugin_base.PATH, "assets", "no_repeat.png")
28+
self.repeat_states = ["off", "track", "context"]
29+
self.icon_paths = [self.no_repeat_icon, self.repeat_one_icon, self.repeat_context_icon]
30+
31+
@property
32+
def get_controller(self) -> SpotifyController:
33+
return self.plugin_base.get_controller
34+
35+
def on_ready(self) -> None:
36+
self.on_update()
37+
self.get_controller.register_update_callback(self.on_update)
38+
39+
def on_key_down(self) -> None:
40+
repeat = self.get_controller.get_repeat_state()
41+
idx = max((self.repeat_states.index(repeat)+1)%3,0)
42+
next_state = self.repeat_states[idx]
43+
next_state_icon = self.repeat_context_icon[idx]
44+
self.get_controller.set_repeat(next_state)
45+
self.set_media(media_path=next_state_icon, size=0.75)
46+
47+
def on_update(self, state=None):
48+
repeat_state = self.get_controller.get_repeat_state(state)
49+
icon = self.icon_paths[self.repeat_states.index(repeat_state)]
50+
self.set_media(media_path=icon, size=0.75)
51+
52+
def on_key_up(self) -> None:
53+
pass

actions/MediaActions/ShuffleAction.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,16 @@ def get_controller(self) -> SpotifyController:
3131
return self.plugin_base.get_controller
3232

3333
def on_ready(self) -> None:
34-
shuffle = self.get_controller.get_shuffle_state()
34+
self.on_update()
35+
self.get_controller.register_update_callback(self.on_update)
36+
37+
def on_key_down(self) -> None:
38+
shuffle = self.get_controller.switch_shuffle()
3539
icon_path = self.shuffle_icon if shuffle else self.no_shuffle_icon
3640
self.set_media(media_path=icon_path, size=0.75)
3741

38-
def on_key_down(self) -> None:
39-
shuffle = self.get_controller.shuffle()
42+
def on_update(self, state=None):
43+
shuffle = self.get_controller.get_shuffle_state(state)
4044
icon_path = self.shuffle_icon if shuffle else self.no_shuffle_icon
4145
self.set_media(media_path=icon_path, size=0.75)
4246

actions/MediaActions/VolumeActions.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,27 @@ def on_key_down(self) -> None:
6060
self.get_controller.set_volume(max(current_volume - 10, 0))
6161

6262

63+
def on_key_up(self) -> None:
64+
pass
65+
66+
class VolumeMute(ActionBase):
67+
def __init__(self, *args, **kwargs):
68+
super().__init__(*args, **kwargs)
69+
self.icon = os.path.join(self.plugin_base.PATH, "assets", "volume_down.png")
70+
71+
72+
@property
73+
def get_controller(self) -> SpotifyController:
74+
return self.plugin_base.get_controller
75+
76+
def on_ready(self) -> None:
77+
icon_path = self.icon
78+
self.set_media(media_path=icon_path, size=0.75)
79+
80+
def on_key_down(self) -> None:
81+
current_volume = self.get_controller.get_volume()
82+
self.get_controller.set_volume(max(current_volume - 10, 0))
83+
84+
6385
def on_key_up(self) -> None:
6486
pass

assets/mute.png

1.94 KB
Loading

main.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from .actions.MediaActions.NextSongAction import Next
99
from .actions.MediaActions.PreviousSongAction import Previous
1010
from .actions.MediaActions.ShuffleAction import Shuffle
11+
from .actions.MediaActions.RepeatAction import Repeat
1112
from .actions.MediaActions.VolumeActions import VolumeDown, VolumeUp
1213

1314
from loguru import logger as log
@@ -60,6 +61,14 @@ def __init__(self):
6061
)
6162
self.add_action_holder(self.previous_holder)
6263

64+
self.previous_holder = ActionHolder(
65+
plugin_base=self,
66+
action_base=Repeat,
67+
action_id="de_outsider_Spotify::Repeat", # Change this to your own plugin id
68+
action_name="Toggle Repeat Mode",
69+
)
70+
self.add_action_holder(self.previous_holder)
71+
6372
self.previous_holder = ActionHolder(
6473
plugin_base=self,
6574
action_base=VolumeUp,
@@ -80,7 +89,7 @@ def __init__(self):
8089
self.register(
8190
plugin_name = "Spotify For StreamController",
8291
github_repo = "https://github.com/bamarc/SpotifyForStreamController",
83-
plugin_version = "0.1.0",
92+
plugin_version = "0.2.0",
8493
app_version = "1.5.0-beta-10"
8594
)
8695

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "0.1.0",
2+
"version": "0.2.0",
33
"thumbnail": "assets/remote.png",
44
"id": "de_outsider_Spotify",
55
"name": "Spotify for StreamController",

0 commit comments

Comments
 (0)