1
# Licensed under the MIT license
2
# http://opensource.org/licenses/mit-license.php
4
# Copyright 2006, Frank Scholz <coherence@beebits.net>
8
from twisted.spread import pb
9
from twisted.internet import reactor
10
from twisted.python import failure
12
from coherence.upnp.core.DIDLLite import classChooser, Container, Resource, DIDLElement
13
from coherence.upnp.core.soap_service import errorCode
17
class ElisaMediaStore:
19
""" this is a backend to the Elisa Media DB
21
Elisa needs to expose two methods
23
get_root_id(media_type)
25
this returns the root id of the media collection
26
if media_type == 'audio'
27
this returns the root id of the audio collection
30
this returns a dict with the following keys:
31
id = id in the media db
32
parent_id = parent_id in the media db
33
name = title, album name or basename
34
mimetype = 'directory' or real mimetype
35
children = list of objects for which this item is the parent
36
location = filesystem path if item is a file
37
cover = url by which the cover image can be retrieved (OPTIONAL)
38
size = in bytes (OPTIONAL)
41
implements = ['MediaServer']
43
def __init__(self, server, **kwargs):
44
self.name = kwargs.get('name','Elisa')
45
self.host = kwargs.get('host','127.0.0.1')
46
self.urlbase = kwargs.get('urlbase','')
47
ignore_patterns = kwargs.get('ignore_patterns',[])
49
if self.urlbase[len(self.urlbase)-1] != '/':
57
return "Elisa storage"
60
factory = pb.PBClientFactory()
62
reactor.connectTCP(self.host, 8789, factory)
63
return factory.getRootObject()
65
def get_by_id(self,id):
67
return self.store[int(id)]
71
def set_root_id( self, id):
73
louie.send('Coherence.UPnP.Backend.init_completed', None, backend=self)
75
def get_root_id( self, media_type='audio'):
76
""" ask Elisa to tell us the id of the top item
77
representing the media_type == 'something' collection """
78
store = self.get_store()
79
dfr = store.addCallback(lambda object:
80
object.callRemote('get_cache_manager'))
81
dfr.addCallback(lambda cache_mgr:
82
cache_mgr.callRemote("get_media_root_id", media_type))
83
dfr.addCallback(self.set_root_id)
88
self.server.connection_manager_server.set_variable(0, 'SourceProtocolInfo',
89
['internal:%s:*:*' % self.host,
90
'http-get:*:audio/mpeg:*'])
92
def upnp_Browse(self, *args, **kwargs):
93
ObjectID = kwargs['ObjectID']
94
BrowseFlag = kwargs['BrowseFlag']
95
Filter = kwargs['Filter']
96
StartingIndex = int(kwargs['StartingIndex'])
97
RequestedCount = int(kwargs['RequestedCount'])
98
SortCriteria = kwargs['SortCriteria']
100
def build_upnp_item(elisa_item):
101
UPnPClass = classChooser(elisa_item['mimetype'])
104
upnp_item = UPnPClass(elisa_item['id'],
105
elisa_item['parent_id'],
107
if isinstance(upnp_item, Container):
108
upnp_item.childCount = len(elisa_item.get('children',[]))
110
upnp_item.searchable = True
111
upnp_item.searchClass = ('object',)
113
internal_url = elisa_item['location'].get('internal')
114
external_url = elisa_item['location'].get('external')
116
size = elisa_item['size']
120
cover = elisa_item['cover']
122
upnp_item.albumArtURI = cover
126
res = Resource(internal_url,
127
'internal:%s:*:*' %self.host)
129
upnp_item.res.append(res)
130
res = Resource(external_url,
131
'http-get:*:%s:*' % elisa_item['mimetype'])
133
upnp_item.res.append(res)
137
def got_result(elisa_item):
139
children = elisa_item.get('children',[])
140
if BrowseFlag == 'BrowseDirectChildren':
141
if RequestedCount == 0:
142
childs = children[StartingIndex:]
144
childs = children[StartingIndex:StartingIndex+RequestedCount]
146
if child is not None:
147
item = build_upnp_item(child)
150
total = len(children)
152
item = build_upnp_item(elisa_item)
157
r = { 'Result': didl.toString(), 'TotalMatches': total,
158
'NumberReturned': didl.numItems()}
160
if hasattr(elisa_item, 'update_id'):
161
r['UpdateID'] = item.update_id
163
r['UpdateID'] = self.update_id
168
return failure.Failure(errorCode(701))
174
store = self.get_store()
175
dfr = store.addCallback(lambda object:
176
object.callRemote('get_cache_manager'))
177
dfr.addErrback(errback)
178
dfr.addCallback(lambda cache_mgr:
179
cache_mgr.callRemote("get_media_node_with_id", id))
180
dfr.addCallback(got_result)
185
if __name__ == '__main__':
190
def got_result(result):
193
f = MediaStore(None,'my media',p, 'http://localhost/',())
195
dfr = f.upnp_Browse(BrowseFlag='BrowseDirectChildren',
201
dfr.addCallback(got_result)
202
dfr.addCallback(lambda _: reactor.stop())
204
reactor.callLater(0.1, main)