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

Able to play music from Apple Music #812

Closed
QW3RTZUI0P opened this issue Feb 25, 2021 · 7 comments · Fixed by #886
Closed

Able to play music from Apple Music #812

QW3RTZUI0P opened this issue Feb 25, 2021 · 7 comments · Fixed by #886

Comments

@QW3RTZUI0P
Copy link

Hey guys,

I am currently working on a Sonos skill for Mycroft AI and therefore need access to music services to play songs. Until recently I used this to control the music, but because Mycroft Skills are written in python and I don’t want extra dependencies to set up I now want to use this package.

But unfortunately I discovered that music services aren’t natively supported here, so I tried to come up with a workaround. Maybe someone else has already come up with my solution and this here is unnecessary, but after a quick search through various issues and PRs I found nothing.
When you start playing a song through the official Sonos app, then call .get_current_track_info() on the speaker and look at the uri value you get something like this: “x-sonos-http:song%3a1193700926.mp4?sid=204&flags=8224&sn=13”
I’m using Apple Music and I noticed that the number behind “3a” is in fact the ID of the played song that you get when you search for it through the iTunes Search API. So using the Search API I’m now able to play certain songs from Apple Music on my speakers by searching for the song, taking the ID, replacing the old ID with the new one and then playing the new uri on my speaker because all the other values like sid, flags and sn stay the same, at least for Apple Music.
I’ve not tested this for other services because I only have and use Apple Music and with certain IDs the song won’t play and the Sonos app shows an error that says that this song is at the moment not available or something similar, but I’ve not figured out with which song IDs this happens.

Has anyone else come up with this yet and have I just not found it then and if not, could anyone try this out with other services?

Also I’m very new to python, GitHub and developing for open source in general, so I might not be the right person to implement this, if this turns out to be of any use.

Thanks,
QW3RTZUI0P

@pwt
Copy link
Contributor

pwt commented Feb 26, 2021

Interesting approach. Obviously, it's Apple Music centric and uses an out-of-band mechanism that differs from the normal way that SoCo does things (entirely via Sonos players). Others will have to comment on if/how it could be added to SoCo.

Music services used to be supported by SoCo, but Sonos changed the way that authentication is implemented. There is work underway in PR #763 to restore support across all services. You may be interested in testing the current code to see if it works with Apple Music?

Note that with Spotify (the only service with which I have experience) it is possible to add Spotify content to Sonos Playlists and Favourites, and to initiate playback in the normal way. So, that provides limited music service support, and it's what I use at the moment.

@QW3RTZUI0P
Copy link
Author

QW3RTZUI0P commented Feb 26, 2021

Hey @pwt, thanks for the quick answer.

I don't quite understand what you mean with the normal way SoCo does things (entirely via Sonos players), but I’ve experimented around a bit this morning and came up with the following:

I’ve gone through some code, especially through this package here from jishi https://github.com/jishi/node-sonos-http-api because it’s able to play songs from Apple Music, Spotify and Amazon Music.

For every service I tried to explain how to create or find the uri which you have to pass to your sonos speakers via soco to play a certain song.

Apple Music:
As can be seen here in line 48, the only things you need to play a song from Apple Music is the song id, the sid, flags and a sn, which are static according to this in line 10. The id can be found through the iTunes Search API.
Example: Let it be by The Beatles: https://itunes.apple.com/search?term=let%20it%20be%20beatles -> resulting id in the json object: 1441133505 -> uri for soco: x-sonos-http:song%3a1441133505.mp4?sid=204&flags=8224&sn=4

Amazon Music:
From https://github.com/jishi/node-sonos-http-api/blob/master/lib/actions/amazonMusic.js in line 13 the uri looks like this: x-sonosapi-hls-static:catalog%2ftracks%2f${id}%2f%3falbumAsin%3dB01JDKZWK0?sid=201&flags=0&sn=4. The id for the song can be found using the web player or anything else and then copying the link to the song. The last number in this link is the song id. I tested this out and for me it worked.

Spotify:
According to this here in line 123 you need exactly the same things to play a song from Spotify as from Apple Music, namely an id, a sid and an accountSN and the uri looks like this: “x-sonos-spotify:spotify%3atrack%3a${id}?sid=${sid}&flags=8224&sn=${accountSN}”.
According to this in line 20 the uri looks like this: “x-sonos-spotify:${encodedSpotifyUri}?sid=${sid}&flags=32&sn=1”.
Also I experimented a bit with my non premium account and took the uri from .get_current_track_info() after starting a Spotify song using the Node JS Http Api and got this:
x-sonos-spotify:spotify:track:TRACK_ID?sid=9&flags=0&sn=19 (TRACK_ID has to be replaced with the Spotify uri you get when you copy the link in the Web interface).

For me the last uri worked to some degree because SoCo added the song I wanted to the queue but gave me an error which said that I cannot play this songs without a premium subscription.
Also I don’t know how these arguments (sid, flags and sn) change, but the sid for your sonos system for spotify can be found using speaker.musicServices.ListAvailableServices() and then looking for Spotify and then the Service Id value and the flags value stays the same with Apple and Amazon Music

Maybe someone of you who has a premium subscription could experiment a bit, try those uris out and provide some short feedback.

Thanks,
QW3RTZUI0P

@pwt
Copy link
Contributor

pwt commented Feb 26, 2021

I don't quite understand what you mean with the normal way SoCo does things (entirely via Sonos players)

I just mean that SoCo delivers all of its functionality via interactions with Sonos players, and does not call out to other APIs such as the iTunes one. However, I don't know the music service code well, so i could easily be wrong!

@amelchio
Copy link
Contributor

We hacked together something like that for Spotify and Tidal in pysonos: https://github.com/amelchio/pysonos/blob/v0.0.40/pysonos/core.py#L1767-L1976 ... it allows enqueuing share URLs from those services.

It is not in a shape where I plan to submit it to SoCo.

@QW3RTZUI0P
Copy link
Author

But could this approach be a potential solution for the music service problem (if it turns out to be working for other services than Apple and Amazon Music) or would it contradict the way SoCo does things (because you need to call external APIs)?
I found this function in the music_services folder and to me it looks like the possibility of playing a song through the format “x-sonos-http…” is known as a “real Sonos URI”. However, this function wants to return an URI in a form like “soco://spotify%3Atrack …” and doesn’t try to replace the ID in the real Sonos URI with the wanted one. Also I don’t know how an URI like “soco://..” should be able to work, because for me at least the provided example (soco://spotify%3Atrack%3A2qs5ZcLByNTctJKbhAZ9JE?sid=2311&sn=1) throws an error.
One remaining problem, at least for Spotify, would be that it would be difficult to get IDs of songs through the Spotify API because you need user authentication, if I’m not mistaken.

@slzatz
Copy link

slzatz commented Jun 18, 2021

I do something similar for Amazon music:

  1. I use the sonos app to put Amazon Music songs I am interested in having convenient access to in the sonos queue.
  2. I have a python program that then takes the song IDs and puts them in a Solr database along with the artist, album, and song title
  3. I access the Amazon Music songs via the command line through another python program so you can do things like:
    1. Shuffle an artists songs
    2. play a specific song or album

This works by searching the Solr db for the songs and then just queueing them up in Sonos via SoCo and playing them.
Really the only drawback of this is having to use the sonos app one time to queue up the songs to get their Amazon ids but its pretty trivial and I periodically just queue up the new music from Amazon that I want to put in the database and that just takes a few minutes. I had created an Alexa skill around all this for my personal use but over time I found that I preferred to type "play xx by yy" or "shuffle whoever" on the command line.

Steve

@amelchio
Copy link
Contributor

The hack that I mentioned above was eventually added to SoCo and it supports Apple Music since #886 (v0.26.0).

@pwt pwt linked a pull request Jan 23, 2022 that will close this issue
@pwt pwt closed this as completed Jan 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants