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

Information about currently played track / context in D-Bus, socket or some other way of communication with a client #1250

Open
ciembor opened this issue Dec 15, 2023 · 7 comments
Labels
enhancement A new feature that would improve Spotifyd

Comments

@ciembor
Copy link

ciembor commented Dec 15, 2023

Is your feature request related to a problem? Please describe.
I'm working on a client that has to be as responsible as possible (manual knobs, button and UI on the screen of a device). Number of requests sent to API is limited and I have to send requests about current track every second to get this info and update UI.

Describe the solution you'd like
Daemon have info about current track already and uses D-Bus to notify about currently playing track / context:

            .emits_changed_false()
            .get(move |_, _| {
                if let Ok(Some(playback)) = sp_client.current_playback(None, None::<Vec<_>>) {
                    if playback.device.name == mv_device_name {
                        if playback.is_playing {
                            return Ok("Playing".to_string());
                        } else {
                            return Ok("Paused".to_string());
                        }
                    }
                }
                Ok("Stopped".to_string())
            });

But I need something more, spotify id of a track / context and type (I'm not sure here, but probably you have different types of contexts). It would be wise to not send these requests from both daemon and client.

Describe alternatives you've considered
I don't know if D-Bus isn't to narrow, sockets might be more universal.

@ciembor ciembor added the enhancement A new feature that would improve Spotifyd label Dec 15, 2023
@Drexel2k
Copy link

Drexel2k commented Dec 15, 2023

Why do you have to request the API every second and not only when something relevant changes? You could listen to PropertiesChanged event/signal on the DBus and only request new information when the track changes e.g.

And the DBus interface is a general MediaPlayer standard:

Maybe in the metadata of the PropertiesChanged signal is also the informatio you need.

If not that would mean adding info beyond the standard somewhere.

@ciembor
Copy link
Author

ciembor commented Dec 15, 2023

@Drexel2k Thank you for link to the DBus documentation, I didn't work with DBus so far and I thought it's more generic, like sockets and allows apps to use their own interfaces. Anyway, I don't want to rely on DBus, my client should work with any device and there are no websockets in Spotify API, so without spotifyd I have to do these requests all the time (that's sad). However I can use DBus if I'm sure spotifyd connection is available.

Oh, and one more thing, I use RaspberryPi and I've read there are problems with efficiency of spotifyd DBus. Is it still the case? Was it somehow fixed or it's something that can't be solved?

@Drexel2k
Copy link

I am new to Linux and Raspberry also, but from my understanding DBus is one standard way of Linux for inter process communication. It works via file links or sockets. I really think all the information you needs IS in the Metadata of the properties changed Event,e.g:

`

('org.mpris.MediaPlayer2.Player',
{'Metadata': ('a{sv}', {'xesam:albumArtist': ('as', ['Daft Punk', 'Pharrell Williams', 'Nile Rodgers']),
'mpris:trackid': ('o', '/spotify/track/2Foc5Q5nqNiosCNqttzHof'),
'xesam:title': ('s', 'Get Lucky (Radio Edit) [feat. Pharrell Williams and Nile Rodgers]'),
'xesam:album': ('s', 'Get Lucky (Radio Edit) [feat. Pharrell Williams and Nile Rodgers]'),
'xesam:trackNumber': ('u', 1), 'xesam:discNumber': ('i', 1),
'mpris:artUrl': ('s', 'https://i.scdn.co/image/ab67616d0000b2731d5cf960a92bb8b03fc2be7f'),
'xesam:url': ('s', 'https://open.spotify.com/track/2Foc5Q5nqNiosCNqttzHof'),
'mpris:length': ('x', 248413000), 'xesam:autoRating': ('d', 0.82),
'xesam:artist': ('as', ['Daft Punk', 'Pharrell Williams', 'Nile Rodgers'])}),
'PlaybackStatus': ('s', 'Playing')},
[])
`

@JJ-Author
Copy link

JJ-Author commented Dec 17, 2023

I also do not really understand what is being proposed / requested here?
I see that the MPRIS interface of spotifyd does not provide all information available in the spotify context (e.g. current playlist id/name is missing, track position also does not work correctly in playlists).
But what information do you actually need?

Anyway, I don't want to rely on DBus, my client should work with any device and there are no websockets in Spotify API, so without spotifyd I have to do these requests all the time (that's sad). However I can use DBus if I'm sure spotifyd connection is available.

I do not understand this. You opened this issue in the spotifyd project, so it makes sense to assume that you have connection to a running version of spotifyd, right?
The only thing I could see here that your client is not running on the same machine as spotifyd but in the same network, and you are looking for a way to discover and control all spotifyd instances in a local and out-of-the-box way (so without using spotify API and special setups like dbus-proxying)

I use RaspberryPi and I've read there are problems with efficiency of spotifyd DBus. Is it still the case? Was it somehow fixed or it's something that can't be solved?

I use it on the super old Pi 1B that has only 220 MB RAM available and it works fast on that old machine (I experienced a stability issue though #1246) fast enough to e.g. poll the playback position 1-2 times a second

see e.g. this

root@DietPi:~# while true; do    time position=$(dbus-send --system --print-reply --dest=org.mpris.MediaPlayer2.spotifyd.instance1840 /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:org.mpris.MediaPlayer2.Player string:Position | grep variant | awk '{print $3}');     echo "Current Position: $position";     sleep 1  # Query every 1 second. Adjust this interval as needed.  
done

real    0m0.240s                                                                                                                                                                   
user    0m0.010s                                                                                                                                                                   
sys     0m0.100s                                                                                                                                                                   
Current Position: 10019000     

@ciembor
Copy link
Author

ciembor commented Dec 17, 2023

@JJ-Author I wasn't aware what is and what isn't available in this protocol, but if you say there is no track / context id, name, information about the type of the context (playlist, artist, album - I use these, maybe there are more types), etc., it would be very nice to have it in metadata delivered from the spotifyd. In other case I have to use Spotify API to get these data for my client. And HTTP request is not as responsive as using local protocol. If such data is already available localy in spotifyd, why duplicate this funcionality?

In general I think all the metadata available in spotifyd should be shared and available from a client. In this or another way (like sockets).

I will write my app in a way where DBus is optional (because I already started without it), but if someone writes something that may work only with spotifyd device, than it would be good strategy.

@JJ-Author
Copy link

JJ-Author commented Dec 17, 2023

As @Drexel2k already wrote the trackid is available. But for other data, you could try to open a "fresh and clean" issue specifying that you would like to have more spotify context metadata on MPRIS or DBUS
But I htink it is tricky to map the information from the context into MPRIS (and some information might not be able to be expressed) and if somebody would commit to implement that^^
I had a look at the spotify client for linux from spotify engineers/developers and it also does not support more metadata (so also no playlist name, no playlist tracklist, etc.) via MPRIS

I personally would do it like this (assuming your client is running on the same device/dbus).

  • I would use a way in the client to detect if a spotify client is running that is using MPRIS
  • if it detects any I would reduce the API request dramatically and only perform them when a change occurred. in order to do so
    • I would subscribe to the Seeked and PropertiesChanged signal on MPRIS/DBUS
    • if an event occured I would inspect which property changed if e.g. the metadata field change then I would fetch all the entire context metadata via the API

I would consider adding some stability features

  • from time to time i would verify whether the DBUS info (e.g. trackid) is the same as reported by the API e.g. compare the trackid
  • i would poll the position with timeouts for the dbus commands every few seconds and if the polls are too slow or hang i would switch back to API for some time interval

here is an example command that subscribes to every MPRIS capable player (also non-spotify ones) for changed properties (e.g. playback status, metadata change)

dbus-monitor "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='/org/mpris/MediaPlayer2',arg0='org.mpris.MediaPlayer2.Player'" 

@eladyn
Copy link
Member

eladyn commented Dec 23, 2023

@JJ-Author In general, I totally agree with your write-up. That sounds like the right thing to do.

i would poll the position with timeouts for the dbus commands every few seconds and if the polls are too slow or hang i would switch back to API for some time interval

However, this is something I would strongly recommend against using, since we (unfortunately) rely on the Spotify API as well, to get the playback position. 😅 So you'll most likely run into 429s when doing this too often. The recommended strategy is:

  • listen to Seeked signal to react to unexpected position changes (like track changes, seeks, play-pause)
  • interpolate the current position based on the last Seeked event

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement A new feature that would improve Spotifyd
Projects
None yet
Development

No branches or pull requests

4 participants