Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi Player Support #2164

Draft
wants to merge 127 commits into
base: future3/develop
Choose a base branch
from

Conversation

Groovylein
Copy link
Collaborator

@Groovylein Groovylein commented Dec 15, 2023

Ground work for multiple players.

Basis to solve Spotify issues or other streaming services on future3, see #1815 and #2116

Groovylein and others added 30 commits November 30, 2021 20:37
- ../shared/audiofolders:/home/pi/RPi-Jukebox-RFID/shared/audiofolders
- ../shared/playlists:/home/pi/.config/mpd/playlists
- ./config/docker.pulse.mpd.conf://home/pi/.config/mpd/mpd.conf
- ../shared/audiofolders:/root/RPi-Jukebox-RFID/shared/audiofolders
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sry for getting at it again, but i still think this should be ${HOME} as it is supplied as args and defaults to "root".
So right now if the user will provide different values it breaks.

@@ -37,6 +37,7 @@ services:
- 5555:5555
- 5556:5556
- 5557:5557
- 3001:3001
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this still belong to the Spotify PR?

player.ctrl.next()

# To get MPD specific playlists
player.mpd.get_album(...)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn’t this be player agnostic?

@pabera pabera changed the title [future3] Multi-player preparation for Spotify etc. [future3] Multi-player Jan 13, 2024
@pabera pabera changed the title [future3] Multi-player Multi Player Support Jan 16, 2024
@pabera pabera added this to the v3.6 milestone Jan 16, 2024
@s-martin
Copy link
Collaborator

s-martin commented Feb 1, 2024

For reference this PR is the base for #2116

@pabera pabera mentioned this pull request Feb 5, 2024
2 tasks
@AlvinSchiller AlvinSchiller mentioned this pull request Feb 14, 2024
@pabera pabera linked an issue Mar 21, 2024 that may be closed by this pull request
Copy link
Collaborator

@pabera pabera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To reduce repetition in your class MPDBackend, where you frequently update self.player_status, you could introduce a decorator that handles the status updates. This way, you won't have to manually call self.player_status.update(playing=True/False) in every method where this is needed. This also keeps your method implementations cleaner and focused on their primary responsibilities.

Decorator Definition (not sure it works directly, but should be close)

def update_player_status(playing=None):
    def decorator(func):
        def wrapper(self, *args, **kwargs):
            result = func(self, *args, **kwargs)
            if playing is not None:
                self.player_status.update(playing=playing)
            return result
        return wrapper
    return decorator

Use the Decorator in Your Class

Apply this decorator to the methods of your MPDBackend class. For methods that set the player to play, pass playing=True, and for those that pause or stop, pass playing=False. You can skip the parameter for methods that don't change the playing status.

class MPDBackend(BackendPlayer): 
    @plugin.tag
    @update_player_status(playing=True)
    def play(self):
        self._active.play()
        
    ...
    @plugin.tag
    @update_player_status()
    def toggle(self):
        self._active.toggle()
        # Dynamically determines playing status based on current state
        current_playing = self.player_status.get_value('playing')
        self.player_status.update(playing=not current_playing)
    
    @plugin.tag
    @update_player_status(playing=False)
    def stop(self):
        self._save_state()
        self._active.stop()

@@ -29,12 +31,23 @@ class PlayerCtrl:
def __init__(self):
self._backends: Dict[str, Any] = {}
self._active = None
self.player_status = None
self.status_poll_interval = 0.25
self.status_thread = multitimer.GenericEndlessTimerClass('player.timer_status',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this! The Timer Classes are pretty well done and can be used for such use cases nicely!

@@ -106,22 +120,30 @@ def prev(self):
@plugin.tag
def play(self):
self._active.play()
self.player_status.update(playing=True)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks rather annoying to add self.player_status.update(playing=True/False) everywhere. You could use a decorator approach, maybe even in the BackendPlayer class (to be verified).

We already use decorators with @plugin.tag.

@maldag
Copy link

maldag commented Sep 5, 2024

Is there any progress on this? How is it being resolved and merged? Last commit is 5 months old

@Groovylein
Copy link
Collaborator Author

Currently no time to develop sorry.
The status is, that the player needs to work with the web app.

The problem is especially the status report to the web app so that the player can be displayed properly.

Feel free to continue ☺️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Podcasts and other players on future3 🐛 | Spotify does not work anymore
7 participants