kpcyrd / spotify-launcher

Client for spotify's apt repository in Rust for Arch Linux
Other
198 stars 15 forks source link

Add support for opening URIs in existing instance #23

Closed vimpostor closed 1 year ago

vimpostor commented 1 year ago

Right now if we open Spotify URLs (for example via Spotify Web -> "Open in Desktop App"), it will always open a new Spotify instance, even if there is already one running and playing music already.

This patch uses Spotify's org.mpris.MediaPlayer2.Player.OpenUri dbus method to open the link in the existing instance instead.

If this dbus call fails for whatever reason, it falls back to opening a new instance (like the old behaviour). Obviously we also first check if an instance already exists, before attempting to call OpenUri.

Demo

https://github.com/vimpostor/blog/assets/21310755/5443f4d4-aec2-401f-971d-e8b73c2a1788

vimpostor commented 1 year ago

@kpcyrd Would you mind taking a look?

kpcyrd commented 1 year ago

hmm, I'm surprised this needs to be done with dbus and isn't possible with the normal binary itself. Maybe the exec is just configured incorrectly in this file? https://github.com/kpcyrd/spotify-launcher/blob/main/contrib/spotify-launcher.desktop

vimpostor commented 1 year ago

Maybe the exec is just configured incorrectly in this file? https://github.com/kpcyrd/spotify-launcher/blob/main/contrib/spotify-launcher.desktop

Nope, it's configured correctly. The Spotify binary just doesn't support this single-instance usage on Linux by default. Luckily the dbus workaround works quite reliable.

vimpostor commented 1 year ago

Hi @kpcyrd, I have been daily driving a spotify-launcher build of this PR for the past months and had absolutely no issues. I think this is a substantial improvement over the stock Spotify behaviour, because users expect music players to act in a "single instance mode" and the upstream Spotify Linux client just starts a new instance for every link you open.

I totally get why you are cautious to merge such features, and for this reason I have just hardened this implementation in multiple ways:

Also note that these URI schemes are not just an implementation detail, Spotify has officially registered them at iana since 2012: https://www.iana.org/assignments/uri-schemes/prov/spotify - so this is not just a hack, this API has been stable for more than 10 years already!

I hope this convinces you to finally review my PR properly. :)

P.S.: With this PR and additionally by using a small proxy default browser, it is possible to open shared Spotify https links directly in Spotify without having to first click "OK" in the browser popup, I might post a blog post about this soon.

vimpostor commented 1 year ago

@kpcyrd Any chance of getting this merged?

I've been using this branch for the last months without problems and in the meantime I wrote a blog post that showcases with a video how seamless Spotify works for me now. I think you will agree with this feature if you check it out.

If you still feel uneasy about these changes even despite all the hardening techniques that I explained in the previous comment, then we can also disable this feature by default: The config option already exists!

Please let me know what I can do to get this patch accepted, I think it will be very useful for all Arch Linux users.

kpcyrd commented 1 year ago

Sorry for being so slow to respond, I've commented on others issues (#26, #25, #28) that I'm trying to stay clear of doing anything beyond "unpack and execute the application" for license reasons.

I wanted to take some more time when writing a reply due to all the work you've put into this and then didn't manage to reply for months, sorry. 😿

vimpostor commented 1 year ago

anything beyond "unpack and execute the application"

I don't really see how this pull request goes beyond the scope of "executing/launching" the application. I understand your reasoning for any of the linked issues, especially for #25 where it would be against the Spotify EULA, but for me launching Spotify by playing an URL over dbus is very much still in line with "launcher functionality", especially because this doesn't change anything in Spotify (just the way that it is launched).

for license reasons

I can only assume you are referring to Spotify's no-redistribution policy, however we already got an ok for repackaging without hosting, otherwise this whole spotify-launcher repo would be illegal without this PR anyway:

So I wanted to let you know that repackaging of the client without hosting it for others is ok.
Under these conditions, Linux hobbyists won't be hunted down by a pack of Spotify wolves.

This PR doesn't change anything affecting this policy and doesn't affect in any way how Spotify itself operates, just how it is launched.

I understand where you are coming from and that as a trusted Arch user you are required to properly conform to the license, but quite frankly launching Spotify links over dbus is about on the same level of modification to the official binary as passing extra arguments to it, which you are doing just fine already.

I don't know if you will reconsider your decision, but either way this repo is already in legal grey-area - with or without this PR.

kpcyrd commented 1 year ago

I found some time for more extensive testing and I can not reproduce the original bug (possibly has been fixed in the meantime by spotify itself, or it's specific to your setup).

The specific steps I used for testing:

1) Install spotify from the testing apt repository (http://repository.spotify.com testing non-free), using an apt implementation of your choice (apt-get, aptitude, spotify-launcher, ...) 2) Start the spotify application with no arguments (active view is then the home screen) 3) Open a webbrowser, navigate to open.spotify.com and login 4) In the browser, navigate to "Liked Songs", rightclick on any song, pick the last menu option "Open in Desktop app"

Opening it in the Desktop app may sometimes also start playing that track, this seems to be dependent on a list of conditions in the desktop app that I haven't fully figured out (is a track currently playing, is a track active but paused, is the "currently playing" device remote, etc)

Results on various systems:

Opening something in the desktop app has not opened a second instance during all testing.

The failure to navigate on ubuntu is because the Linux executable only understands arguments starting with --, but /usr/share/spotify/spotify.desktop from the official package specifies Exec=spotify %U. This is causing the desktop environment to either execute spotify (when clicking on the menu item) or spotify spotify:track:... (when using it as a protocol handler), but the executable is expecting spotify --uri=spotify:track:... according to spotify --help. I'm not sure this is possible to implement with .desktop files, hopefully the spotify executable starts accepting positional arguments at some point. 🤞

I did not reverse engineer in detail how the spotify executable detects already existing spotify instances, but using strace -f I noticed it's (successfully) connecting to unix domain sockets at /run/dbus/system_bus_socket, /tmp/.X11-unix/X0 and /run/user/1000/bus, this may not be working correctly on your system. You could also try ~/.local/share/spotify-launcher/install/usr/bin/spotify --show-console.

vimpostor commented 1 year ago

First, thanks for taking the time to investigate this. I can confirm that something has changed in Spotify's implementation (it's probably just a sideeffect of updating their CEF version), and I am no longer able to start two instances. But the new behaviour is also far from what I would consider correct.

I also seem to get some slightly different behaviour than you, using Spotify version 1.2.13.661.ga588f749 on Arch Linux with KDE Plasma (via spotify-launcher) clicking on "Open in Desktop App" brings up the application to the front, navigates to the album/song and the current song is interrupted (but the new one does not play, instead playback is cleared completely): Screenshot_20230815_153658

Debugging what Spotify does reveals that the website attempts to xdg-open the URI spotify:track:4rPv8eZH6ABfkrtxxHHtV4?context=spotify%3Aartist%3A0QWrMNukfcVOmgEU0FEDyD. The problematic part is the metadata part. Indeed, running

xdg-open spotify:track:4rPv8eZH6ABfkrtxxHHtV4?context=spotify%3Aartist%3A0QWrMNukfcVOmgEU0FEDyD

in a terminal reveals the same broken behaviour, while removing the metadata part i.e. just

xdg-open spotify:track:4rPv8eZH6ABfkrtxxHHtV4

works and does play the track in the already running Spotify app.

In any case this pull request is a superset of that now half-working functionality. This pull request also allows Spotify to work with the spotify:// and https:// URIs, which is useful if you want to avoid the browser altogether.

To convince you why this PR is still fixing tons of functionality, here is a table overview of what currently works with official Spotify and what works with this PR:

URI scheme Official Spotify / spotify-launcher spotify-launcher + this PR
spotify:track:id ✔ ✔
spotify:track:id?context=ctx ✗ ✔
spotify://track/id ✗ ✔
spotify://track/id?context=ctx ✗ ✔
https://open.spotify.com/track/id ✗ ✔
https://open.spotify.com/track/id?si=si ✗ ✔

For the test case scenario I used the same test as above, i.e. have already running Spotify open, run spotify-launcher $URI and observe how it either doesn't work at all or has completely broken behaviour. Opening spotify:track:id without context metadata was the only one on my end that was not broken.

using strace -f I noticed it's (successfully) connecting to unix domain sockets at /run/dbus/system_bus_socket, /tmp/.X11-unix/X0 and /run/user/1000/bus

This is probably just a sideeffect of Spotify being built on CEF and Chromium doing unrelated stuff over dbus...

P.S.: What about disabling the already existing option in this PR by default, and giving it a slightly different name, maybe play_over_dbus or something? :)