Created
October 18, 2016 04:55
-
-
Save nickrobson/fbcd09cd755e256c5ea3ac175029e334 to your computer and use it in GitHub Desktop.
Gets your Sonos speaker's queue.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import requests | |
import xml.etree.cElementTree as XML | |
SOAP_TEMPLATE = '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body>{0}</s:Body></s:Envelope>' | |
GET_QUEUE_BODY_TEMPLATE = '<u:Browse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1"><ObjectID>Q:0</ObjectID><BrowseFlag>BrowseDirectChildren</BrowseFlag><Filter>dc:title,res,dc:creator,upnp:artist,upnp:album,upnp:albumArtURI</Filter><StartingIndex>{0}</StartingIndex><RequestedCount>{1}</RequestedCount><SortCriteria></SortCriteria></u:Browse>' | |
def cmd(sonos_ip, endpoint, soap_action, body): | |
headers = { | |
'Content-Type': 'application/json', | |
'SOAPACTION': soap_action | |
} | |
soap = SOAP_TEMPLATE.format(body) | |
r = requests.post('http://' + sonos_ip + ':1400' + endpoint, data=soap, headers=headers) | |
return r.content | |
def get_queue(sonos_ip, start = 0, max = 100): | |
endpoint = '/MediaServer/ContentDirectory/Control' | |
soap = 'urn:schemas-upnp-org:service:ContentDirectory:1#Browse' | |
body = GET_QUEUE_BODY_TEMPLATE.format(start, max) | |
res = cmd(sonos_ip, endpoint, soap, body) | |
queue = [] | |
try: | |
dom = XML.fromstring(res.encode('utf-8')) | |
resultText = dom.findtext('.//Result') | |
if not resultText: | |
return queue | |
dom = XML.fromstring(resultText.encode('utf-8')) | |
for element in dom.findall('.//{urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/}item'): | |
try: | |
item = {} | |
item['uri'] = element[0].text | |
item['duration'] = element[0].attrib['duration'] | |
item['album_art'] = element[1].text | |
item['title'] = element[2].text | |
item['artist'] = element[4].text | |
item['album'] = element[5].text | |
queue.append(item) | |
except: | |
logger.warning('Could not handle item: %s', element) | |
except Exception as e: | |
print e.__name__ + ':', e | |
return queue | |
if __name__ == '__main__': | |
print 'To get your Sonos IP, go into the Sonos Controller app' | |
print 'Once there, you can go either [Sonos > About My Sonos System] or [Help > About My Sonos System]' | |
print json.dumps(get_queue(raw_input('Sonos IP: '))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you for this! I actually have a couple Sonos devices, which naturally surfaced the fact that each potentially has a distinct queue. I was able to use python-zeroconf to discover their IP addresses. This is my edited version.
Also, at least with the data returned by my devices, I couldn't count on every returned
element
having at least 6 children, so I had to defend againstIndexError
.I tried to account for grouping, but I think a proper solution would use the actual Sonos API. Similarly, the Sonos API would presumably get me the user-friendly names of the devices.