Skip to content

Instantly share code, notes, and snippets.

@pwt
Created November 3, 2019 15:02
Show Gist options
  • Save pwt/f518a5178b9655f7678bb8a076a3d682 to your computer and use it in GitHub Desktop.
Save pwt/f518a5178b9655f7678bb8a076a3d682 to your computer and use it in GitHub Desktop.
# This is proof of concept code to experiment with adding music library shares to Sonos.
# Unlike other UPnP operations, adding shares is done over HTTPS, presumably to avoid transmitting
# the username and password for the share in clear text.
#
# Using Wireshark to observe the traffic between the a Sonos controller and player while adding a share,
# the HTTPS port used is 1443.
#
# The required UPnP action is assumed to be:
#
# ContentDirectory:CreateObject
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Input
# ContainerID: string
# Elements: string
# Output
# ObjectID: string
# Result: string
from sys import argv
import requests
import soco
# HTTPS requests go to port 1443
# Placeholder for the Sonos player IP address
request_address_format = "https://{}:1443/ContentDirectory/CreateObject"
# Placeholders for ContainerID (share path) and Elements (string = ???)
payload_format = (
'<?xml version="1.0" encoding="utf-8"?>'
'<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'
'<s:Body>'
'<u:CreateObject xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">'
'<ContainerID>S:{}</ContainerID>'
'<Elements>{}</Elements>'
'</u:CreateObject>'
'</s:Body>'
'</s:Envelope>'
)
def add_share(soco_instance, container_id, elements):
req_addr = request_address_format.format(soco_instance.ip_address)
req_payload = payload_format.format(container_id, elements)
req_headers = {
"Content-Type": "application/xml",
"SOAPAction": "urn:schemas-upnp-org:service:ContentDirectory:1#CreateObject"
}
return requests.post(req_addr, data=req_payload,
headers=req_headers, verify=False)
if __name__ == "__main__":
if len(argv) != 3:
print('Usage:', __file__, '<ContainerID> <Elements>')
exit()
soco_instance = soco.discovery.any_soco()
response = add_share(soco_instance, argv[1], argv[2])
print('Result: status_code = ', response.status_code, ', reason = ',
response.reason, sep='')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment