def spotify_add_album(device, service, service_id, pos=0): ''' Add a spotify album to the queue. Seems to work also with an artist's TopTracks and Radio. Parameters: device: a soco device (eg device = list(soco.discover())[0].group.coordinator) service: a spotify music service object (eg soco.music_services.MusicService('Spotify')) service_id: the spotify id of the album to be added (eg 'spotify:album:5qo7iEWkMEaSXEZ7fuPvC3') pos: the desired position in the queue, or 0 for the end of the queue Returns: The enqueued position of the first item, as returned by device ''' item_id = '0fffffff{0}'.format(quote_url(service_id)) meta = '''<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" \ xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" \ xmlns:r="urn:schemas-rinconnetworks-com:metadata-1-0/" \ xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/">\ <item id="{0}" parentID="DUMMY" restricted="true">\ <dc:title>DUMMY</dc:title>\ <upnp:class>object.container.album.musicAlbum</upnp:class>\ <desc id="cdudn" nameSpace="urn:schemas-rinconnetworks-com:metadata-1-0/">{1}</desc>\ </item></DIDL-Lite>'''.format(item_id, service.desc) try: response = device.avTransport.AddURIToQueue([ ('InstanceID', 0), ('EnqueuedURI', 'x-rincon-cpcontainer:' + item_id), ('EnqueuedURIMetaData', meta), ('DesiredFirstTrackNumberEnqueued', pos), ('EnqueueAsNext', 1 if pos == 0 else 0) ]) return int(response['FirstTrackNumberEnqueued']) except Exception as ex: print(ex)
def AddToQueue(artist = '', song = '', url = '', queue_position = 0, playnow = False, keepinqueue = True): if not url: results = service.search(category='tracks', term=song) tracks = results.items().pop()[1] for track in tracks: currentArtist = track.items()[4][1].items()[1][1] if currentArtist == artist: break #track_id = "spotify:track:2qs5ZcLByNTctJKbhAZ9JE" track_id = track.items()[0][1] else: segmentedurl = urlparse.urlparse(url) segmentedpath = segmentedurl[2].split('/') trackHash = segmentedpath[len(segmentedpath) - 1] track_id = "spotify:track:" + trackHash didl = DidlMusicTrack( title="DUMMY", # This is ignored. Sonos gets the title from the item_id parent_id="DUMMY", # Ditto item_id="0fffffff{0}".format(quote_url(track_id)), desc=service.desc ) meta = to_didl_string(didl) # Add it to the queue and play it response = sonos.avTransport.AddURIToQueue([ ("InstanceID", 0), ("EnqueuedURI", service.sonos_uri_from_id( track_id)), ("EnqueuedURIMetaData", meta), ("DesiredFirstTrackNumberEnqueued", queue_position), ("EnqueueAsNext", 1) ]) index = int(response["FirstTrackNumberEnqueued"]) - 1 if playnow: sonos.play_from_queue(index, True) if not keepinqueue: thr = threading.Thread(target=RemoveItemFromQueue, args=[index], kwargs={}) thr.start() # will run "foo" return True
def add_track_to_queue(self, track: Union[deezer.resources.Track, str, int], position: Optional[int] = None): """Add a track into Sonos queue. :param track: Deezer Track object or Deezer track identifier :param position: Position into the queue, None to the end of the queue. """ if isinstance(track, deezer.resources.Track): track_id = str(track.id) elif isinstance(track, (str, int)): track_id = str(track) else: raise TypeError("Invalid `track` argument") del track track_id = str(track_id) dz_track = self.__dz.get_track(track_id) album_id = dz_track.get_album().id position = self.__valid_queue_position(position) prefix_item_id = prefix_id.get('track') prefix_parent_id = prefix_id.get('album') item_id = quote_url(f"tr:{track_id}") uri = f"x-sonos-http:{item_id}?sid=2&sn=0" resource = DidlResource(protocol_info="sonos.com-http:*:audio/mp4:*", uri=uri) didl = DidlAudioItem(item_id=f"{prefix_item_id}{item_id}", parent_id=f"{prefix_parent_id}album-{album_id}", title=dz_track.title, desc=self.__ms.desc, resources=[ resource, ], restricted=False) self.__add_uri_to_queue(uri, didl, position)
def add_from_service(self, item_id, service, is_track=True): # The DIDL item_id is made of the track_id (url escaped), but with an 8 # (hex) digit prefix. It is not clear what this is for, but it doesn't # seem to matter (too much) what it is. We can use junk (thought the # first digit must be 0 or 1), and the player seems to do the right # thing. Real DIDL items sent to a player also have a title and a # parent_id (usually the id of the relevant album), but they are not # necessary. The flow charts at http://musicpartners.sonos.com/node/421 # and http://musicpartners.sonos.com/node/422 suggest that it is the job # of the player, not the controller, to call get_metadata with a track # id, so this might explain why no metadata is needed at this stage. # NB: quote_url will break if given unicode on Py2.6, and early 2.7. So # we need to encode. if self.device is None: return item_id = quote_url(item_id.encode('utf-8')) didl_item_id = "0fffffff{0}".format(item_id) # For an album: if not is_track: uri = 'x-rincon-cpcontainer:' + didl_item_id else: # For a track: uri = service.sonos_uri_from_id(item_id) res = [DidlResource(uri=uri, protocol_info="Snips")] didl = DidlItem( title="Snips", # This is ignored. Sonos gets the title from the item_id parent_id="Snips", # Ditto item_id=didl_item_id, desc=service.desc, resources=res) self.device.add_to_queue(didl)
def add_from_service(item_id, service, device, is_track=True): # The DIDL item_id is made of the track_id (url escaped), but with an 8 # (hex) digit prefix. It is not clear what this is for, but it doesn't # seem to matter (too much) what it is. We can use junk (thought the # first digit must be 0 or 1), and the player seems to do the right # thing. Real DIDL items sent to a player also have a title and a # parent_id (usually the id of the relevant album), but they are not # necessary. The flow charts at http://musicpartners.sonos.com/node/421 # and http://musicpartners.sonos.com/node/422 suggest that it is the job # of the player, not the controller, to call get_metadata with a track # id, so this might explain why no metadata is needed at this stage. # NB: quote_url will break if given unicode on Py2.6, and early 2.7. So # we need to encode. item_id = quote_url(item_id.encode('utf-8')) didl_item_id = "0fffffff{0}".format(item_id) # For an album: if not is_track: uri = 'x-rincon-cpcontainer:' + didl_item_id else: # For a track: uri = service.sonos_uri_from_id(item_id) res = [DidlResource(uri=uri, protocol_info="DUMMY")] didl = DidlItem(title="DUMMY", # This is ignored. Sonos gets the title from the item_id parent_id="DUMMY", # Ditto item_id=didl_item_id, desc=service.desc, resources=res) device.add_to_queue(didl)