librespot icon indicating copy to clipboard operation
librespot copied to clipboard

Add MPRIS support

Open paulfariello opened this issue 3 months ago • 10 comments

Taking back on @wisp3rwind work for adding MPRIS support #1341.

  • Rebased on recent dev branch
  • ensure cargo fmt and cargo clippy passes on each commit
  • fix a few todos
  • send signal when position changed
  • return error when MPRIS command are done in wrong context or internal fails
  • handle position
  • handle identity
  • choose biggest art url
  • ensure metadata are always up to date or at least not invalid
  • notify on various property change

Not sure about:

  • Sending current state of player for all new listener (59767ce)

paulfariello avatar Sep 23 '25 08:09 paulfariello

@roderickvd this PR can probably be considered ready. The only missing feature is to handle the track list. It can probably be done in another PR.

Right now, CI is failing but doesn't seems to be related to this specific PR.

Do you have an opinion concerning 59767ce which is a broader modification than just MPRIS support?

paulfariello avatar Sep 30 '25 15:09 paulfariello

@roderickvd this PR can probably be considered ready. The only missing feature is to handle the track list. It can probably be done in another PR.

Thanks! I saw you processed quite a bit of comments after, so ping me when you feel you're ready for another round of review.

Do you have an opinion concerning 59767ce which is a broader modification than just MPRIS support?

What'd be the negatives? 😄 No honestly. It seems like an improvement to me, but let me know if I should be aware of any downsides.

roderickvd avatar Oct 06 '25 19:10 roderickvd

Don't forget to add a changelog entry.

roderickvd avatar Oct 06 '25 19:10 roderickvd

Don't forget to add a changelog entry.

Done in 0a5c3aac31a4f5327b2ee34c5fd8fd6142bb6021

paulfariello avatar Oct 08 '25 08:10 paulfariello

@roderickvd this PR can probably be considered ready. The only missing feature is to handle the track list. It can probably be done in another PR.

Thanks! I saw you processed quite a bit of comments after, so ping me when you feel you're ready for another round of review.

AFAICT I've rework everything raised by comment. Should be ok for a last review.

Do you have an opinion concerning 59767ce which is a broader modification than just MPRIS support?

What'd be the negatives? 😄 No honestly. It seems like an improvement to me, but let me know if I should be aware of any downsides.

If you don't see any negatives then let's go with that :)

paulfariello avatar Oct 08 '25 08:10 paulfariello

Small reminder that everything seems ready for last review here

paulfariello avatar Oct 18 '25 11:10 paulfariello

👍 I’m away for a few days before I can review, but if anyone wants to beat me to it…

roderickvd avatar Oct 18 '25 17:10 roderickvd

Just tested it on KDE Medial player doesn't show title and control's

image

Official spotify client:

image

If it’s possible, I’d love to sponsor this work a bit

andriyor avatar Nov 16 '25 21:11 andriyor

@andriyor could you check the following command on both dbus services (org.mpris.MediaPlayer2.librespot and the one used by official client).

dbus-send --print-reply --dest=REPLACE_WITH_DBUS_SERVICE --type=method_call --print-reply /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.GetAll "string:REPLACE_WITH_DBUS_SERVICE"

If you don't know the official spotify client service name use the following command:

dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames

paulfariello avatar Nov 18 '25 15:11 paulfariello

spotify:

❯ dbus-send --print-reply \
  --dest=org.mpris.MediaPlayer2.spotify \  
  --type=method_call \
  /org/mpris/MediaPlayer2 \
  org.freedesktop.DBus.Properties.GetAll \
  string:"org.mpris.MediaPlayer2.Player"

method return time=1763494565.329229 sender=:1.305 -> destination=:1.308 serial=213 reply_serial=2
   array [
      dict entry(
         string "PlaybackStatus"
         variant             string "Playing"
      )
      dict entry(
         string "LoopStatus"
         variant             string "None"
      )
      dict entry(
         string "Rate"
         variant             double 1
      )
      dict entry(
         string "Shuffle"
         variant             boolean false
      )
      dict entry(
         string "Metadata"
         variant             array [
               dict entry(
                  string "mpris:trackid"
                  variant                      string "/com/spotify/track/4GKJALTXTwhZgLPp0usd5C"
               )
               dict entry(
                  string "mpris:length"
                  variant                      uint64 268906000
               )
               dict entry(
                  string "mpris:artUrl"
                  variant                      string "https://i.scdn.co/image/ab67616d0000b273b23737878e75582c2e255029"
               )
               dict entry(
                  string "xesam:album"
                  variant                      string "Skinty Fia"
               )
               dict entry(
                  string "xesam:albumArtist"
                  variant                      array [
                        string "Fontaines D.C."
                     ]
               )
               dict entry(
                  string "xesam:artist"
                  variant                      array [
                        string "Fontaines D.C."
                     ]
               )
               dict entry(
                  string "xesam:autoRating"
                  variant                      double 0.7
               )
               dict entry(
                  string "xesam:discNumber"
                  variant                      int32 1
               )
               dict entry(
                  string "xesam:title"
                  variant                      string "Roman Holiday"
               )
               dict entry(
                  string "xesam:trackNumber"
                  variant                      int32 6
               )
               dict entry(
                  string "xesam:url"
                  variant                      string "https://open.spotify.com/track/4GKJALTXTwhZgLPp0usd5C"
               )
            ]
      )
      dict entry(
         string "Volume"
         variant             double 0.53109
      )
      dict entry(
         string "Position"
         variant             int64 16842000
      )
      dict entry(
         string "MinimumRate"
         variant             double 1
      )
      dict entry(
         string "MaximumRate"
         variant             double 1
      )
      dict entry(
         string "CanGoNext"
         variant             boolean true
      )
      dict entry(
         string "CanGoPrevious"
         variant             boolean true
      )
      dict entry(
         string "CanPlay"
         variant             boolean true
      )
      dict entry(
         string "CanPause"
         variant             boolean true
      )
      dict entry(
         string "CanSeek"
         variant             boolean true
      )
      dict entry(
         string "CanControl"
         variant             boolean true
      )
   ]

~ 

librespot:

❯ dbus-send --print-reply \
  --dest=org.mpris.MediaPlayer2.librespot \
  --type=method_call \
  /org/mpris/MediaPlayer2 \
  org.freedesktop.DBus.Properties.GetAll \
  string:"org.mpris.MediaPlayer2.Player"

method return time=1763494469.425111 sender=:1.288 -> destination=:1.291 serial=58 reply_serial=2
   array [
      dict entry(
         string "MinimumRate"
         variant             double 1
      )
      dict entry(
         string "PlaybackStatus"
         variant             string "Playing"
      )
      dict entry(
         string "Position"
         variant             int64 76107000
      )
      dict entry(
         string "CanControl"
         variant             boolean true
      )
      dict entry(
         string "MaximumRate"
         variant             double 1
      )
      dict entry(
         string "Shuffle"
         variant             boolean false
      )
      dict entry(
         string "CanGoPrevious"
         variant             boolean true
      )
      dict entry(
         string "CanPause"
         variant             boolean true
      )
      dict entry(
         string "CanPlay"
         variant             boolean true
      )
      dict entry(
         string "Rate"
         variant             double 1
      )
      dict entry(
         string "LoopStatus"
         variant             string "None"
      )
      dict entry(
         string "CanGoNext"
         variant             boolean true
      )
      dict entry(
         string "CanSeek"
         variant             boolean true
      )
      dict entry(
         string "Metadata"
         variant             array [
               dict entry(
                  string "mpris:artUrl"
                  variant                      string "https://i.scdn.co/image/ab67616d0000b273b23737878e75582c2e255029"
               )
               dict entry(
                  string "mpris:length"
                  variant                      int64 268906000
               )
               dict entry(
                  string "mpris:trackId"
                  variant                      object path "/org/librespot/track/4GKJALTXTwhZgLPp0usd5C"
               )
               dict entry(
                  string "xesam:album"
                  variant                      string "Skinty Fia"
               )
               dict entry(
                  string "xesam:albumArtist"
                  variant                      array [
                        string "Fontaines D.C."
                     ]
               )
               dict entry(
                  string "xesam:artist"
                  variant                      array [
                        string "Fontaines D.C."
                     ]
               )
               dict entry(
                  string "xesam:contentCreated"
                  variant                      string "2022-04-22T00:00:00.000000000Z"
               )
               dict entry(
                  string "xesam:discNumber"
                  variant                      int32 1
               )
               dict entry(
                  string "xesam:trackNumber"
                  variant                      int32 6
               )
            ]
      )
      dict entry(
         string "Volume"
         variant             double 0.499992
      )
   ]

~ 
❯ 

I found that unofficial widget supports it: https://github.com/ccatterina/plasmusic-toolbar

image

andriyor avatar Nov 18 '25 19:11 andriyor