coherence.backends.picasa_storage — Cohen3 0.8.0 documentation

# Source code for coherence.backends.picasa_storage

    # Licensed under the MIT license
    # http://opensource.org/licenses/mit-license.php

    # Copyright 2009, Jean-Michel Sizun
    # Copyright 2009 Frank Scholz <coherence@beebits.net>

    import gdata.geo
    import gdata.media
    import gdata.photos.service
    from twisted.internet import threads

    from coherence.backend import BackendItem, Container, \
        LazyContainer, \
        AbstractBackendStore
    from coherence.upnp.core import DIDLLite
    from coherence.upnp.core.utils import ReverseProxyUriResource

    class PicasaProxy(ReverseProxyUriResource):

        def __init__(self, uri):
            ReverseProxyUriResource.__init__(self, uri)

        def render(self, request):
            if 'referer' in request.received_headers:
                del request.received_headers['referer']
            return ReverseProxyUriResource.render(self, request)

    class PicasaPhotoItem(BackendItem):
        def __init__(self, photo):
            BackendItem.__init__(self)
            # print photo
            self.photo = photo

            self.name = photo.summary.text
            if self.name is None:
                self.name = photo.title.text

            self.duration = None
            self.size = None
            self.mimetype = photo.content.type
            self.description = photo.summary.text
            self.date = None
            self.item = None

            self.photo_url = photo.content.src
            self.thumbnail_url = photo.media.thumbnail[0].url

            self.url = None

            self.location = PicasaProxy(self.photo_url)

        def replace_by(self, item):
            # print photo
            self.photo = item.photo
            self.name = self.photo.summary.text
            if self.name is None:
                self.name = self.photo.title.text
            self.mimetype = self.photo.content.type
            self.description = self.photo.summary.text
            self.photo_url = self.photo.content.src
            self.thumbnail_url = self.photo.media.thumbnail[0].url
            self.location = PicasaProxy(self.photo_url)
            return True

        def get_item(self):
            if self.item is None:
                upnp_id = self.get_id()
                upnp_parent_id = self.parent.get_id()
                self.item = DIDLLite.Photo(
                    upnp_id, upnp_parent_id, self.name)
                res = DIDLLite.Resource(
                    self.url, f'http-get:*:{self.mimetype}:*')
                self.item.res.append(res)
            self.item.childCount = 0
            return self.item

        def get_path(self):
            return self.url

        def get_id(self):
            return self.storage_id

    class PicasaStore(AbstractBackendStore):
        logCategory = 'picasa_store'

        implements = ['MediaServer']

        description = (
            'Picasa Web Albums',
            'connects to the Picasa Web Albums service and exposes the '
            'featured photos and albums for a given user.',
            None)

        options = [
            {'option': 'name', 'text': 'Server Name:', 'type': 'string',
             'default': 'my media',
             'help': 'the name under this MediaServer shall '
                     'show up with on other UPnP clients'},
            {'option': 'version', 'text': 'UPnP Version:', 'type': 'int',
             'default': 2, 'enum': (2, 1),
             'help': 'the highest UPnP version this MediaServer shall support',
             'level': 'advance'},
            {'option': 'uuid', 'text': 'UUID Identifier:', 'type': 'string',
             'help': 'the unique (UPnP) identifier for this MediaServer, '
                     'usually automatically set',
             'level': 'advance'},
            {'option': 'refresh', 'text': 'Refresh period',
             'type': 'string'},
            {'option': 'login', 'text': 'User ID:', 'type': 'string',
             'group': 'User Account'},
            {'option': 'password', 'text': 'Password:', 'type': 'string',
             'group': 'User Account'},
        ]

        def __init__(self, server, **kwargs):
            AbstractBackendStore.__init__(self, server, **kwargs)

            self.name = kwargs.get('name', 'Picasa Web Albums')

            self.refresh = int(kwargs.get('refresh', 60)) * 60

            self.login = kwargs.get('userid', kwargs.get('login', ''))
            self.password = kwargs.get('password', '')

            rootContainer = Container(None, self.name)
            self.set_root_item(rootContainer)

            self.AlbumsContainer = LazyContainer(
                rootContainer, 'My Albums', None,
                self.refresh, self.retrieveAlbums)
            rootContainer.add_child(self.AlbumsContainer)

            self.FeaturedContainer = LazyContainer(
                rootContainer, 'Featured photos',
                None, self.refresh,
                self.retrieveFeaturedPhotos)
            rootContainer.add_child(self.FeaturedContainer)

            self.init_completed()

        def __repr__(self):
            return self.__class__.__name__

        def upnp_init(self):
            self.current_connection_id = None

            if self.server:
                self.server.connection_manager_server.set_variable(
                    0,
                    'SourceProtocolInfo',
                    'http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=01;'
                    'DLNA.ORG_FLAGS=00f00000000000000000000000000000,'
                    'http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=01;'
                    'DLNA.ORG_FLAGS=00f00000000000000000000000000000,'
                    'http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED;DLNA.ORG_OP=01;'
                    'DLNA.ORG_FLAGS=00f00000000000000000000000000000,'
                    'http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_OP=01;'
                    'DLNA.ORG_FLAGS=00f00000000000000000000000000000,'
                    'http-get:*:image/jpeg:*,'
                    'http-get:*:image/gif:*,'
                    'http-get:*:image/png:*',
                    default=True)

            self.wmc_mapping = {'16': self.get_root_id()}

            self.gd_client = gdata.photos.service.PhotosService()
            self.gd_client.email = self.login
            self.gd_client.password = self.password
            self.gd_client.source = 'Coherence UPnP backend'
            if len(self.login) > 0:
                d = threads.deferToThread(self.gd_client.ProgrammaticLogin)

        def retrieveAlbums(self, parent=None):
            albums = threads.deferToThread(self.gd_client.GetUserFeed)

            def gotAlbums(albums):
                if albums is None:
                    print('Unable to retrieve albums')
                    return
                for album in albums.entry:
                    title = album.title.text
                    album_id = album.gphoto_id.text
                    item = LazyContainer(parent, title, album_id, self.refresh,
                                         self.retrieveAlbumPhotos,
                                         album_id=album_id)
                    parent.add_child(item, external_id=album_id)

            def gotError(error):
                print(f'ERROR: {error}')

            albums.addCallbacks(gotAlbums, gotError)
            return albums

        def retrieveFeedPhotos(self, parent=None, feed_uri=''):
            # print feed_uri
            photos = threads.deferToThread(self.gd_client.GetFeed, feed_uri)

            def gotPhotos(photos):
                if photos is None:
                    print(f'Unable to retrieve photos for feed {feed_uri}')
                    return
                for photo in photos.entry:
                    photo_id = photo.gphoto_id.text
                    item = PicasaPhotoItem(photo)
                    item.parent = parent
                    parent.add_child(item, external_id=photo_id)

            def gotError(error):
                print(f'ERROR: {error}')

            photos.addCallbacks(gotPhotos, gotError)
            return photos

        def retrieveAlbumPhotos(self, parent=None, album_id=''):
            album_feed_uri = \
                f'/data/feed/api/user/{self.login}/albumid/{album_id}?kind=photo'
            return self.retrieveFeedPhotos(parent, album_feed_uri)

        def retrieveFeaturedPhotos(self, parent=None):
            feed_uri = 'http://picasaweb.google.com/data/feed/api/featured'
            return self.retrieveFeedPhotos(parent, feed_uri)