# Licensed under the MIT license
# http://opensource.org/licenses/mit-license.php
# Copyright 2007, Frank Scholz <coherence@beebits.net>
# Copyright 2008, Jean-Michel Sizun <jm.sizun@free.fr>
from coherence.extern.galleryremote import Gallery
from twisted.internet import defer
from coherence.backend import BackendItem
from coherence.backend import BackendStore
from coherence.upnp.core.DIDLLite import classChooser, Container, Resource
from coherence.upnp.core.utils import ReverseProxyUriResource
[docs]class ProxyGallery2Image(ReverseProxyUriResource):
def __init__(self, uri):
ReverseProxyUriResource.__init__(self, uri)
[docs] def render(self, request):
del request.received_headers['referer']
return ReverseProxyUriResource.render(self, request)
[docs]class Gallery2Item(BackendItem):
logCategory = 'gallery2_item'
def __init__(self, id, obj, parent, mimetype, urlbase, UPnPClass,
update=False):
BackendItem.__init__(self)
self.id = id
self.name = obj.get('title') # .encode('utf-8')
if self.name is None:
self.name = obj.get('name')
if self.name is None:
self.name = id
self.mimetype = mimetype
self.gallery2_id = obj.get('gallery2_id')
self.parent = parent
if parent:
parent.add_child(self, update=update)
if parent is None:
parent_id = -1
else:
parent_id = parent.get_id()
self.item = UPnPClass(id, parent_id, self.name)
if isinstance(self.item, Container):
self.item.childCount = 0
self.child_count = 0
self.children = None
if len(urlbase) and urlbase[-1] != '/':
urlbase += '/'
if parent is None:
self.gallery2_url = None
self.url = urlbase + str(self.id)
elif self.mimetype == 'directory':
# self.gallery2_url = parent.store.get_url_for_album(
# self.gallery2_id)
self.url = urlbase + str(self.id)
else:
self.gallery2_url = parent.store.get_url_for_image(
self.gallery2_id)
self.url = urlbase + str(self.id)
self.location = ProxyGallery2Image(self.gallery2_url)
if self.mimetype == 'directory':
self.update_id = 0
else:
res = Resource(self.gallery2_url,
'http-get:*:%s:*' % self.mimetype)
res.size = None
self.item.res.append(res)
[docs] def remove(self):
if self.parent:
self.parent.remove_child(self)
del self.item
[docs] def add_child(self, child, update=False):
if self.children is None:
self.children = []
self.children.append(child)
self.child_count += 1
if isinstance(self.item, Container):
self.item.childCount += 1
if update:
self.update_id += 1
[docs] def remove_child(self, child):
# self.info("remove_from %d (%s) child %d (%s)" % (
# self.id, self.get_name(), child.id, child.get_name()))
if child in self.children:
self.child_count -= 1
if isinstance(self.item, Container):
self.item.childCount -= 1
self.children.remove(child)
self.update_id += 1
[docs] def get_children(self, start=0, request_count=0):
def process_items(result=None):
if self.children is None:
return []
if request_count == 0:
return self.children[start:]
else:
return self.children[start:request_count]
if self.children is None:
d = self.store.retrieveItemsForAlbum(self.gallery2_id, self)
d.addCallback(process_items)
return d
else:
return process_items()
[docs] def get_child_count(self):
return self.child_count
[docs] def get_id(self):
return self.id
[docs] def get_update_id(self):
if hasattr(self, 'update_id'):
return self.update_id
else:
return None
[docs] def get_path(self):
return self.url
[docs] def get_name(self):
return self.name
[docs] def get_parent(self):
return self.parent
[docs] def get_item(self):
return self.item
[docs] def get_xml(self):
return self.item.toString()
def __repr__(self):
return 'id: ' + str(self.id)
[docs]class Gallery2Store(BackendStore):
logCategory = 'gallery2_store'
implements = ['MediaServer']
description = (
'Gallery2',
'exposes the photos from a Gallery2 photo repository.',
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': 'server_url', 'text': 'Server URL:',
'type': 'string'},
{'option': 'username', 'text': 'User ID:', 'type': 'string',
'group': 'User Account'},
{'option': 'password', 'text': 'Password:', 'type': 'string',
'group': 'User Account'},
]
def __init__(self, server, **kwargs):
BackendStore.__init__(self, server, **kwargs)
self.next_id = 1000
self.config = kwargs
self.name = kwargs.get('name', 'gallery2Store')
self.wmc_mapping = {'16': 1000}
self.update_id = 0
self.store = {}
self.gallery2_server_url = self.config.get('server_url',
'http://localhost/gallery2')
self.gallery2_username = self.config.get('username', None)
self.gallery2_password = self.config.get('password', None)
self.store[1000] = Gallery2Item(
1000, {'title': 'Gallery2',
'gallery2_id': '0',
'mimetype': 'directory'},
None, 'directory', self.urlbase, Container, update=True)
self.store[1000].store = self
self.gallery2_remote = Gallery(self.gallery2_server_url, 2)
if None not in [self.gallery2_username, self.gallery2_password]:
d = self.gallery2_remote.login(self.gallery2_username,
self.gallery2_password)
d.addCallback(lambda x: self.retrieveAlbums('0', self.store[1000]))
d.addCallback(self.init_completed)
else:
d = self.retrieveAlbums('0', self.store[1000])
d.addCallback(self.init_completed)
def __repr__(self):
return self.__class__.__name__
[docs] def append(self, obj, parent):
if isinstance(obj, str):
mimetype = 'directory'
else:
mimetype = obj['mimetype']
UPnPClass = classChooser(mimetype)
id = self.getnextID()
update = False
# if hasattr(self, 'update_id'):
# update = True
item = Gallery2Item(id, obj, parent, mimetype, self.urlbase,
UPnPClass, update=update)
self.store[id] = item
self.store[id].store = self
if hasattr(self, 'update_id'):
self.update_id += 1
if self.server:
self.server.content_directory_server.set_variable(
0, 'SystemUpdateID', self.update_id)
# if parent:
# value = (parent.get_id(),parent.get_update_id())
# if self.server:
# self.server.content_directory_server.set_variable(
# 0, 'ContainerUpdateIDs', value)
if mimetype == 'directory':
return self.store[id]
return None
[docs] def len(self):
return len(self.store)
[docs] def get_by_id(self, id):
if isinstance(id, str):
id = id.split('@', 1)[0]
elif isinstance(id, bytes):
id = id.decode('utf-8').split('@', 1)[0]
try:
id = int(id)
except ValueError:
id = 1000
if id == 0:
id = 1000
try:
return self.store[id]
except KeyError:
return None
[docs] def getnextID(self):
self.next_id += 1
return self.next_id
[docs] def get_url_for_image(self, gallery2_id):
url = self.gallery2_remote.get_URL_for_image(gallery2_id)
return url
[docs] 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)
[docs] def retrieveAlbums(self, album_gallery2_id, parent):
d = self.gallery2_remote.fetch_albums()
def gotAlbums(albums):
if albums:
albums = [
album for album in list(albums.values()) if
album.get('parent') == album_gallery2_id]
if album_gallery2_id == '0' and len(albums) == 1:
album = albums[0]
self.store[1000].gallery2_id = album.get('name')
self.store[1000].name = album.get('title')
self.store[1000].description = album.get('summary')
else:
for album in albums:
gallery2_id = album.get('name')
parent_gallery2_id = album.get('parent')
title = album.get('title')
description = album.get('summary')
store_item = {
'name': id,
'gallery2_id': gallery2_id,
'parent_id': parent_gallery2_id,
'title': title,
'description': description,
'mimetype': 'directory',
}
self.append(store_item, parent)
d.addCallback(gotAlbums)
return d
[docs] def retrieveItemsForAlbum(self, album_id, parent):
# retrieve subalbums
d1 = self.retrieveAlbums(album_id, parent)
# retrieve images
d2 = self.gallery2_remote.fetch_album_images(album_id)
def gotImages(images):
if images:
for image in images:
image_gallery2_id = image.get('name')
parent_gallery2_id = image.get('parent')
thumbnail_gallery2_id = image.get('thumbName')
resized_gallery2_id = image.get('resizedName')
title = image.get('title')
description = image.get('description')
gallery2_id = resized_gallery2_id
if gallery2_id == '':
gallery2_id = image_gallery2_id
store_item = {
'name': id,
'gallery2_id': gallery2_id,
'parent_id': parent_gallery2_id,
'thumbnail_gallery2_id': thumbnail_gallery2_id,
'title': title,
'description': description,
'mimetype': 'image/jpeg',
}
self.append(store_item, parent)
d2.addCallback(gotImages)
dl = defer.DeferredList([d1, d2])
return dl
[docs]def main():
f = Gallery2Store(None)
def got_upnp_result(result):
print("upnp", result)
f.upnp_init()
if __name__ == '__main__':
from twisted.internet import reactor
reactor.callWhenRunning(main)
reactor.run()