1
2
3
4
5
6
7 """ Content Directory service implementation.
8
9 Common usage is to just add a ContentDirectory class instance to a device.
10 """
11
12 import os.path
13
14 from brisa.core import log, plugin_manager
15 from brisa.upnp.device import Service
16 from brisa.upnp.didl.didl_lite import Element
17 from brisa.upnp.services.xmls import xml_path
18
19
20 log = log.getLogger('services.cds')
21
22 service_name = 'ContentDirectory'
23 service_type = 'urn:schemas-upnp-org:service:ContentDirectory:1'
24 scpd_xml_path = os.path.join(xml_path, 'content-directory-scpd.xml')
25
26
28 """ Compares two DIDL objects by their title for proper sorting.
29
30 @param a: A DIDL object to be compared with.
31 @param b: A DIDL object to compare with.
32
33 @type a: DIDL
34 @type b: DIDL
35
36 @return: The comparation result.
37 @rtype: boolean
38 """
39 if a.title.lower().startswith("all "):
40 return -1
41
42 if b.title.lower().startswith("all "):
43 return 1
44
45 return cmp(a.title.lower(), b.title.lower())
46
47
48 -class ContentDirectory(Service):
49 """ Content Directory service implementation (version 1.0).
50 """
51
52 - def __init__(self, plugins_folder, plugins_module_str):
53 Service.__init__(self, service_name, service_type, '', scpd_xml_path)
54 self.plugin_manager = plugin_manager.PluginManager(plugins_folder,
55 plugins_module_str)
56 self.updateID = 0
57
59 """ Starts the ContentDirectory by loading the plugins.
60 """
61 self.plugin_manager.load_plugins()
62
64 """ Stops the ContentDirectory servie by unloading the plugins.
65 """
66 self.plugin_manager.unload_plugins()
67
68 - def publish(self, webserver):
71
72 - def soap_GetSearchCapabilities(self, *args, **kwargs):
73 """ Returns the search capabilities supported by the device.
74
75 @param args: list of arguments for the GetSearchCapabilities UPnP\
76 function
77 @param kwargs: dict of arguments for the GetSearchCapabilities UPnP\
78 function
79
80 @type args: list
81 @type kwargs: dict
82
83 @return: the search capabilities supported by the device
84 @rtype: dict
85 """
86 log.debug('Action on ContentDirectory: GetSearchCapabilities()')
87
88
89 return {'SearchCaps': ''}
90
91 - def soap_GetSortCapabilities(self, *args, **kwargs):
92 """ Returns the CSV list of meta-data tags that can be used in
93 sortCriteria.
94
95 @param args: list of arguments for the GetSortCapabilities UPnP\
96 function
97 @param kwargs: dict of arguments for the GetSortCapabilities UPnP\
98 function
99
100 @type args: list
101 @type kwargs: dict
102
103 @return: CSV list of meta-data
104 @rtype: dict
105 """
106 log.debug('Action on ContentDirectory: GetSortCapabilities()')
107 return {'SortCaps': 'dc:title'}
108
109 - def soap_GetSystemUpdateID(self, *args, **kwargs):
110 """ Returns the current value of state variable SystemUpdateID.
111
112 @param args: list of arguments for the GetSystemUpdateID UPnP\
113 function
114 @param kwargs: dict of arguments for the GetSystemUPdateID UPnP\
115 function
116
117 @type args: list
118 @type kwargs: dict
119
120 @return: current value of SystemUpdateID
121 @rtype: dict
122 """
123 log.debug('Action on ContentDirectory: GetSystemUpdateID()')
124 return {'Id': self.updateID}
125
126 - def soap_Browse(self, *args, **kwargs):
127 """ Implements the Browse action for the ContentDirectory.
128
129 @param args: list of arguments for the Browse UPnP\
130 function
131 @param kwargs: dict of arguments for the Browse UPnP\
132 function
133
134 @type args: list
135 @type kwargs: dict
136
137 @return: the results of the browsing
138 @rtype: dict
139 """
140 log.debug('Action on ContentDirectory: Browse%s', args)
141
142 args = (kwargs['ObjectID'], kwargs['BrowseFlag'], kwargs['Filter'],
143 kwargs['StartingIndex'], kwargs['RequestedCount'],
144 kwargs['SortCriteria'])
145 l = {}
146 l['query'] = 'Browse(ObjectID=%s, BrowseFlags=%s, Filter=%s, ' \
147 'StartingIndex=%s RequestedCount=%s SortCriteria=%s)' % \
148 tuple(map(repr, args))
149 try:
150 ret = self._soap_Browse(*args)
151 except Exception, e:
152 log.error('Action Browse on ContentDirectory: %s', e.message)
153
154 l['response'] = ret
155
156 return ret
157
158 - def _soap_Browse(self, *args):
159 """ Real implementation of the soap browse.
160
161 @param args: list of arguments
162 @type args: list
163
164 @return: the results of browsing
165 @rtype: dict
166 """
167 (object_id, browse_flag, filter, starting_index, requested_count,
168 sort_criteria) = args
169 try:
170 starting_index = int(starting_index)
171 requested_count = int(requested_count)
172 last_index = None
173 plugin = self.plugin_manager.root_plugin
174
175 if browse_flag == 'BrowseDirectChildren' and \
176 requested_count != 0:
177 last_index = requested_count + starting_index
178
179 if ':' in object_id:
180 namespace = object_id.split(':')[0]
181 plugin = self.plugin_manager.plugins_instances[namespace]
182
183 if not plugin:
184 log.error('Could not get plugin associated with this'\
185 'browse action on id %s' % object_id)
186
187 elements = plugin.browse(object_id, browse_flag, filter,
188 starting_index, requested_count,
189 sort_criteria)
190
191 elements.sort(cmp=compare_objects)
192 didl = Element()
193 total = 0
194
195 if plugin.has_browse_filter:
196 for item in elements:
197 didl.add_item(item)
198 total = total + 1
199 else:
200 for item in elements[starting_index: last_index]:
201 didl.add_item(item)
202 total = total + 1
203
204 didl_xml = didl.to_string()
205 soap_result = {'Result': didl_xml,
206 'TotalMatches': len(elements),
207 'NumberReturned': total,
208 'UpdateID': self.updateID}
209 except Exception, e:
210 soap_result = {'Result': '',
211 'TotalMatches': 0,
212 'NumberReturned': 0,
213 'UpdateID': self.updateID}
214 log.error('ContentDirectory.Browse internal problem: %s', e)
215
216 return soap_result
217
218 - def soap_Search(self, *args, **kwargs):
219 """ Search for objects that match some search criteria.
220
221 @param args: list of arguments for the Search UPnP function
222 @param kwargs: dict of arguments for the Search UPnP function
223
224 @type args: list
225 @type kwargs: dict
226
227 TODO: forward the search to the respective plugin.
228 TODO: implement the search.
229 """
230 return {'Result': '',
231 'NumberReturned': 0,
232 'TotalMatches': 0,
233 'UpdateID': self.updateID}
234