Album Art URI

371 views
Skip to first unread message

Rob

unread,
May 20, 2014, 2:58:57 AM5/20/14
to pytho...@googlegroups.com

Hi All,

I thought that I'd create a new post for each separate discussion point (hope that is OK).

I have noticed that the 'album_art_uri' that is returned for tracks, album etc is not the complete URI, for example:

/getaa?u=x-file-cifs%3a%2f%2f192.168.0.3%2fMusic%2fFLAC%2fQueen%2fGreatest%2520Hits%2f05%2520-%2520Bicycle%2520Race.flac&v=10

This means that in order to actually access this, every time I have to retrieve the IP address of the given Sonos system and construct the URL myself:

full_album_art_uri = 'http://' + soco.ip_address + ':1400' + album_art_uri

I was wondering if it would be possible/make sense, for this to be done under the covers in soco?

Somthing like a property that does this for you on MLTrack, MLAlbum

Thoughts?

Thanks

Rob

Rob

unread,
May 21, 2014, 1:09:33 PM5/21/14
to pytho...@googlegroups.com

The partial album_art_uri does also seem to be at odds with the 'album_art' value returned via the get_current_track_info() method, which seems to return the complete URL.

Thanks

Rob

Kenneth Nielsen

unread,
May 21, 2014, 1:36:07 PM5/21/14
to pytho...@googlegroups.com
Hallo Rob

I principle yes, the data structure items could create the complete URI, but the problem is, that the data structures are meant to be player independent and persistent. So that you could e.g. create a cache the MLTracks, store them locally and use them in another instance without having to worry about say a network change that made the IPs change. Since the album art uri for music lib items would contain the IP, doing the conversion under the hood would violate that principle. However, obviously your are right, that it sucks having to do the conversion your self. The two options for implementing this I see are:

1) To add another methods to the data structures that returns the complete URI, but requires a SoCo instance as an argument (i.e. the SoCo instance that you want to fetch the album art from). so something like MLTrack.complete_album_art_uri(soc)
2) To create a method in the SoCo class that can convert the uri, so: SoCo.get_music_lib_album_art_uri(MLTrack).

I think I may lean towards the latter.

BTW, this actually also explain why the get_current_track_info method knows the complete URI, it is because that info comes from the SoCo instance that know its own IP.

Rob

unread,
May 21, 2014, 4:09:33 PM5/21/14
to pytho...@googlegroups.com

Hi Kenneth,

As the interface I'm calling is

soco.get_music_library_information(...)
soco.get_queue(...)

These are being called on given instances of soco's, so they already have the IP address etc. (And after all, the queue is a queue on a given instance).  So if the "rule" is, if you call it on an instance of soco (like get_current_track_info) they should have the full URI, then shouldn't these?

Either way, I have put together a class that extends the soco class, and tweaks the return etc.

In case it's of any use to anyone else:

class Sonos(SoCo):
    # Format of the meta data (borrowed from sample code)
    meta_template = '<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="R:0/0/0" parentID="R:0/0" restricted="true"><dc:title>{title}</dc:title><upnp:class>object.item.audioItem.audioBroadcast</upnp:class><desc id="cdudn" nameSpace="urn:schemas-rinconnetworks-com:metadata-1-0/">{service}</desc></item></DIDL-Lite>'
    tunein_service = 'SA_RINCON65031_'

    # Converts non complete URIs to complete URIs with IP address
    def _updateAlbumArtToFullUri(self, musicInfo):
        if hasattr(musicInfo, 'album_art_uri'):
            # Add on the full album art link, as the URI version does not include the ipaddress
            if (musicInfo.album_art_uri != None) and (musicInfo.album_art_uri != ""):
                if not musicInfo.album_art_uri.startswith(('http:', 'https:')):
                    musicInfo.album_art_uri = 'http://' + self.ip_address + ':1400' + musicInfo.album_art_uri

    # Override method so that the album art http reference can be added
    def get_music_library_information(self, search_type, start=0, max_items=100):
        # Call the base version
        musicInfo = SoCo.get_music_library_information(self, search_type, start, max_items)

        # Make sure the album art URI is the full path
        self._updateAlbumArtToFullUri(musicInfo)

        return musicInfo

    # Override method so that the album art http reference can be added
    def get_queue(self, start = 0, max_items = 100):
        list = SoCo.get_queue(self, start=start, max_items=max_items)
       
        if list != None:
            for anItem in list:
                # Make sure the album art URI is the full path
                self._updateAlbumArtToFullUri(anItem)
       
        return list

    # For radio playing a title is required
    def play_uri(self, uri='', title=None, metadata=''):
        # Radio stations need to have at least a title to play
        if (metadata == '') and (title != None):
            title_esc = cgi.escape(title)
            metadata = Sonos.meta_template.format(title=title_esc, service=Sonos.tunein_service)

        # Need to replace any special characters in the URI
        uri = cgi.escape(uri)
        # Now play the track
        SoCo.play_uri(self, uri, metadata)

    # Need to override the add_to_queue method as in 0.7 it forces you to have
    # metadata - that we do not have
    def add_to_queue(self, uri):
        queueitem = [
            ('InstanceID', 0),
            ('EnqueuedURI', uri),
            ('EnqueuedURIMetaData', ''),
            ('DesiredFirstTrackNumberEnqueued', 0),
            ('EnqueueAsNext', 1)
        ]
        response = self.avTransport.AddURIToQueue(queueitem)

        qnumber = response['FirstTrackNumberEnqueued']
        return int(qnumber)


Thanks for you continued assistance.

Rob



Kenneth Nielsen

unread,
May 22, 2014, 5:37:17 PM5/22/14
to pytho...@googlegroups.com
I see your point. I think I was a little unclear. The point is more about direction and independence of the ml objects. The queue and get_current_track_info methods return stuff that is not meant to be re-added or to be long time durable, the queue just tells you what the queue is now. The music library data structures on the other hand are meant to be re-added to the queue and they should work independently of the python session and ip addresses. As an example, the official Sonos player most likely creates a local data base over all music in the local music library, now, of it wants to show the album art, then it is no good if the information in the data base is invalid, because the ip-addresses of the speakers have changed in the mean time. That is why, in my view, it is better to not do it right away, but to simply offer a method to do the conversion. On a side note, only the music library items suffer from this problem, because the music service items most often link to sources on the internet.

Regards Kenneth
Reply all
Reply to author
Forward
0 new messages