def add_album_to_queue(self, spotify_album): """ Add a spotify album to the queue using the SpotifyAlbum class """ if not spotify_album.satisfied(): spotify_album = self._add_album_metadata(spotify_album) res = [ DidlResource(uri=spotify_album.uri, protocol_info="x-rincon-playlist:*:*:*"), ] item = DidlObject(spotify_album.title, '', spotify_album.spotify_uri, resources=res) return self.soco.add_to_queue(item)
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_album_to_queue(self, album: Union[deezer.resources.Album, str, int], position: Optional[int] = None): """Add an album into Sonos queue. :param album: Deezer Album object or Deezer album identifier :param position: Position into the queue, None to the end of the queue. """ if isinstance(album, deezer.resources.Album): album_id = str(album.id) elif isinstance(album, (str, int)): album_id = str(album) else: raise TypeError("Invalid `album` argument") del album dz_album = self.__dz.get_album(album_id) artist_id = dz_album.get_artist().id position = self.__valid_queue_position(position) prefix_item_id = prefix_id.get('album') prefix_parent_id = prefix_id.get('user-albums') item_id = f"{prefix_item_id}album-{album_id}" uri = f"x-rincon-cpcontainer:{item_id}" resource = DidlResource(protocol_info="x-rincon-cpcontainer:*:*:*", uri=uri) didl = DidlAlbum( item_id=item_id, parent_id=f"{prefix_parent_id}user-albums-{artist_id}", title=dz_album.title, desc=self.__ms.desc, resources=[ resource, ], restricted=False) self.__add_uri_to_queue(uri, didl, position)
def add_playlist_to_queue(self, playlist: Union[deezer.resources.Playlist, str, int], position: Optional[int] = None): """Add an playlist into Sonos queue. :param playlist: Deezer playlist object or Deezer playlist identifier :param position: Position into the queue, None to the end of the queue. """ if isinstance(playlist, deezer.resources.Playlist): playlist_id = str(playlist.id) elif isinstance(playlist, (str, int)): playlist_id = str(playlist) else: raise TypeError("Invalid `playlist` argument") del playlist dz_playlist = self.__dz.get_playlist(playlist_id) position = self.__valid_queue_position(position) prefix_parent_id = prefix_id.get('user-albums') item_id = f"{prefix_parent_id}playlist_spotify%3aplaylist-{playlist_id}" uri = f"x-rincon-cpcontainer:{item_id}" resource = DidlResource(protocol_info="x-rincon-cpcontainer:*:*:*", uri=uri) didl = DidlPlaylistContainer( item_id=item_id, parent_id= f"{prefix_parent_id}playlist_spotify:playlist-{playlist_id}", title=dz_playlist.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 handle_library_item(uri): global spkr global album_prefix logger.info('PLAYING FROM LIBRARY: ' + uri) # TODO: re-implement queue-building as in chrispcampbell original ############ # # Playing albums # ############# # to playback, construct a dummy DidlMusicAlbum to send to sonos queue # needed to play album: URI, and album_id # all albums share URI, which is: # x-rincon-playlist:RINCON_[uuid of sonos zone] # album_id can be got from QR code. It looks like: # alb:A:ALBUM/Bone%20Machine # albums can also be hashed. they look like: # alb:hsh:[hashed_id] if 'alb:' in uri: # if this is a 'hashed' album, get album id from hashed resource if 'hsh:' in uri: with open(hashed_albums, 'rb') as r: b = pickle.loads(r.read()) album_id = b[uri] else: album_id = uri[4:] album_fullURI = album_prefix + '#' + album_id logging.info('sending full uri %s' % (album_fullURI)) # SoCo needs a DidlResource object to play albums # We can construct a 'dummy' DidlResource with generic metadata, # and when this is passed to the speaker, SoCo/Sonos will be able to fetch # the album from the music library. res = [DidlResource(uri=album_fullURI, protocol_info='dummy')] didl = soco.data_structures.DidlMusicAlbum(title='dummy', parent_id='dummy', item_id=album_id, resources=res) spkr.clear_queue() spkr.add_to_queue(didl) spkr.play() ######## # # Playing playlists or tracks # ######### # to playback, you need only the URI of the playlist/track, # which comes in one of two forms. # Sonos playlist looks like: # file:///jffs/settings/savedqueues.rsq#0 # Imported itunes playlist looks like: # x-file-cifs://computer/music/iTunes/iTunes%20Music%20Library.xml#9D1D3FDCFDBB6751 # Track looks like: # x-file-cifs://computer/music/iTunes/Music/Original%20Soundtrack/Chants%20From%20The%20Thin%20Red%20Line/01%20Jisas%20Yu%20Hand%20Blong%20Mi.mp3 elif 'pl:' in uri: pluri = uri[3:] spkr.clear_queue() spkr.add_uri_to_queue(uri=pluri) spkr.play() elif 'trk:' in uri: # look up hashuri in hashed tracks with open(hashed_tracks, 'rb') as r: b = pickle.loads(r.read()) trkuri = b[uri] spkr.clear_queue() spkr.add_uri_to_queue(uri=trkuri) spkr.play()