4.2.5r2
[enigma2.git] / usr / lib / enigma2 / python / Plugins / SystemPlugins / UPnP / DreamboxMediaStore.py
1 # -*- coding: utf-8 -*-
2
3 """
4 This is a Media Backend that allows you to access audio, videos and live-streams on
5 a Dreambox.
6 """
7
8 from enigma import eMediaDatabase, eServiceReference, StringList
9 from Components.config import config
10 from Components.ResourceManager import resourcemanager
11 from Components.Sources.ServiceList import ServiceList
12 from Tools.Log import Log
13
14 from coherence.backend import ROOT_CONTAINER_ID, AbstractBackendStore, Container
15 from coherence.upnp.core import DIDLLite
16 from coherence.upnp.core.soap_service import errorCode
17
18 from twisted.internet import defer
19
20 from UPnPCore import DLNA, removeUPnPDevice
21
22 from coherence.extern.et import ET
23 from twisted.python import failure
24
25 import sys
26 if sys.getdefaultencoding() != 'UTF-8':
27         reload(sys)
28         sys.setdefaultencoding('UTF-8')
29
30 def convertString(string):
31         return str(string).encode('utf-8', 'replace')
32
33 class RootContainer(Container):
34         def get_item(self):
35                 if self.item is None:
36                         self.item = DIDLLite.Container(self.storage_id, self.parent_id, self.name)
37                 self.item.childCount = len(self.children)
38                 return self.item
39
40 class BaseContainer(RootContainer):
41         def __init__(self, parent, name):
42                 RootContainer.__init__(self, parent, convertString(name))
43
44         def _set_item_defaults(self, searchClass=[]):
45                 if self.children is None:
46                         self.get_children()
47                 if self.children:
48                         self.item.childCount = self.get_child_count()
49                 self.item.date = None
50                 self.item.genre = None
51                 self.item.searchable = True
52                 self.item.searchClass = searchClass
53
54 class DBContainer(BaseContainer):
55         ITEM_KEY_TITLE = "title"
56         ITEM_KEY_ID = "id"
57         ITEM_KEY_CATEGORY = "category"
58
59         def __init__(self, db, name, parent):
60                 BaseContainer.__init__(self, parent, name)
61                 self._db = db
62                 self.location = None
63                 self.item = None
64                 self.children = None
65                 self._default_mime = "audio/mpeg"
66                 self._default_additionalInfo = "*"
67
68         def get_path(self):
69                 return self.location
70
71         def get_item(self):
72                 if self.item is None:
73                         self.item = DIDLLite.Item(self.get_id(), self.parent.get_id(), self.name, restricted=True)
74                         self._set_item_defaults()
75                         self.update_id += 1
76                 return self.item
77
78         def _get_data(self, res):
79                 if res and not res.error():
80                         return res.data()
81                 elif res:
82                         self.warning("%s\n%s" % (res.errorDriverText(), res.errorDatabaseText()))
83                 else:
84                         self.warning("res is %s", res)
85                 return []
86
87         def _set_item_resources(self, codec, size=0, duration=0, resolution=None):
88                         if size < 0:
89                                 size = 0
90                         mimetype = DLNA.getMimeType(codec, self._default_mime)
91                         dlna_params = DLNA.getParams(mimetype)
92
93                         ext = self.location.split('.')[-1]
94                         url = "%s%s.%s" % (self.store.urlbase, self.get_id(), ext)
95
96                         res = DIDLLite.Resource(data=url, protocolInfo='http-get:*:%s:%s' % (mimetype, dlna_params))
97                         res.size = size
98
99                         m, s = divmod(duration, 60)
100                         h, m = divmod(m, 60)
101                         res.duration = "%d:%02d:%02d.000" % (h, m, s)
102                         res.resolution = resolution
103                         self.item.res.append(res)
104
105         def _set_item_defaults(self, searchClass=[]):
106                 BaseContainer._set_item_defaults(self, searchClass)
107                 self.item.genre = _("Unknown")
108
109 class Artist(DBContainer):
110         schemaVersion = 1
111         mimetype = 'directory'
112
113         def __init__(self, db, name, parent, isAlbumArtist=False):
114                 DBContainer.__init__(self, db, name, parent)
115                 self._isAlbumArtist = isAlbumArtist
116
117         def _do_get_children(self, start, end):
118                 return self._db.getAlbumsByArtist(self.name)
119
120         def get_children(self, start=0, end=0):
121                 if self.children is None:
122                         res = self._do_get_children(start, end)
123                         items = self._get_data(res)
124                         self.children = []
125                         if len(items) > 1:
126                                 self.add_child(ArtistAll(self._db, self.name, _("-- All --"), self, isAlbumArtist=self._isAlbumArtist))
127                         for item in items:
128                                 self.add_child(Album(self._db, item, self, isAlbumArtist=self._isAlbumArtist))
129                 return DBContainer.get_children(self, start, end)
130
131         def get_item(self):
132 #               self.warning(self.name)
133                 if self.item is None:
134                         self.item = DIDLLite.MusicArtist(self.get_id(), self.parent.get_id(), self.name, restricted=True)
135                         self._set_item_defaults(searchClass="object.item.audioItem")
136                 return self.item
137
138 class AlbumArtist(Artist):
139         schemaVersion = 1
140         mimetype = 'directory'
141
142         def __init__(self, db, name, parent):
143                 Artist.__init__(self, db, name, parent, isAlbumArtist=True)
144
145         def _do_get_children(self, start, end):
146                 return self._db.getAlbumsByAlbumArtist(self.name)
147
148 class Artists(DBContainer):
149         schemaVersion = 1
150         mimetype = 'directory'
151
152         def get_children(self, start=0, end=0):
153                 if self.children is None:
154                         res = self._db.getAllArtists()
155                         Log.i(self.name)
156                         items = self._get_data(res)
157                         self.children = []
158                         for item in items:
159                                 self.add_child(Artist(self._db, item[eMediaDatabase.FIELD_ARTIST], self))
160                 return DBContainer.get_children(self, start, end)
161
162         def get_item(self):
163                 if self.item is None:
164                         self.item = DIDLLite.Music(self.get_id(), self.parent.get_id(), self.name, restricted=True)
165                         self._set_item_defaults(searchClass="object.item.audioItem")
166                 return self.item
167
168 class AlbumArtists(Artists):
169         schemaVersion = 1
170         mimetype = 'directory'
171
172         def get_children(self, start=0, end=0):
173                 if self.children is None:
174                         res = self._db.getAllAlbumArtists()
175                         Log.i(self.name)
176                         items = self._get_data(res)
177                         self.children = []
178                         for item in items:
179                                 self.add_child(AlbumArtist(self._db, item[eMediaDatabase.FIELD_ARTIST], self))
180                 return DBContainer.get_children(self, start, end)
181
182 class AudioAll(DBContainer):
183         schemaVersion = 1
184         mimetype = 'directory'
185
186         def get_children(self, start=0, end=0):
187                 if self.children is None:
188                         Log.i(self.name)
189                         self.children = []
190                         res = self._db.getAllAudio()
191                         items = self._get_data(res)
192                         for item in items:
193                                 self.add_child(Track(self._db, item, self, combinedTitle=True))
194                 return DBContainer.get_children(self, start, end)
195
196         def get_item(self):
197                 Log.i(self.item)
198                 if self.item is None:
199                         self.item = DIDLLite.Music(self.get_id(), self.parent.get_id(), self.name, restricted=True)
200                         self._set_item_defaults(searchClass="object.item.audioItem")
201                 return self.item
202
203 class Album(DBContainer):
204         schemaVersion = 1
205         mimetype = 'directory'
206
207         def __init__(self, db, item, parent, isAlbumArtist=False):
208                 artist, album, album_id = item[eMediaDatabase.FIELD_ARTIST], item[eMediaDatabase.FIELD_ALBUM], item[eMediaDatabase.FIELD_ID]
209                 self._db_item = item
210                 self.artist = artist
211                 self.id = int(album_id)
212                 self._isAlbumArtist = isAlbumArtist
213                 DBContainer.__init__(self, db, album, parent)
214
215         def get_children(self, start=0, end=0):
216                 if self.children is None:
217                         self.children = []
218                         if self.id:
219                                 res = self._db.getTracksByAlbumId(self.id)
220                         else:
221                                 if self._isAlbumArtist:
222                                         res = self._db.filterByAlbumArtistAlbum(self.artist, self.name)
223                                 else:
224                                         res = self._db.filterByArtistAlbum(self.artist, self.name)
225                         items = self._get_data(res)
226                         for item in items:
227                                 self.add_child(Track(self._db, item, self))
228                 return DBContainer.get_children(self, start, end)
229
230         def get_item(self):
231                 if self.item is None:
232                         self.item = DIDLLite.MusicAlbum(id=self.get_id(), parentID=self.parent.get_id(), title=self.name, restricted=True)
233                         self._set_item_defaults(searchClass="object.item.audioItem")
234                         self.item.artist = self.artist
235                         self.item.creator = self.artist
236                         if self.id:
237                                 res = self._db.getAlbumCoverArtId(self.id)
238                                 if res and not res.error():
239                                         data = res.data()
240                                         for d in data:
241                                                 for coverid in d.itervalues():
242                                                         if int(coverid) != 0:
243                                                                 self.item.albumArtURI = self.store.getCoverArtUri(coverid)
244 #                                                               Log.d("%s - %s: %s" %(self.artist, self.name, self.item.albumArtURI))
245                                                                 break
246                 return self.item
247
248 class ArtistAll(Album):
249         schemaVersion = 1
250         mimetype = 'directory'
251         def __init__(self, db, artist, name, parent, isAlbumArtist=False):
252                 item = {
253                                 eMediaDatabase.FIELD_ARTIST : artist,
254                                 eMediaDatabase.FIELD_ALBUM : name,
255                                 eMediaDatabase.FIELD_ID : 0
256                         }
257                 Album.__init__(self, db, item, parent, isAlbumArtist=isAlbumArtist)
258
259         def get_children(self, start=0, end=0):
260                 if self.children is None:
261                         self.children = []
262                         if self._isAlbumArtist:
263                                 res = self._db.filterByAlbumArtist(self.parent.name)
264                         else:
265                                 res = self._db.filterByArtist(self.parent.name)
266                         items = self._get_data(res)
267                         for item in items:
268                                 self.add_child(Track(self._db, item, self))
269                 return DBContainer.get_children(self, start, end)
270
271 class Albums(DBContainer):
272         schemaVersion = 1
273         mimetype = 'directory'
274
275         def get_children(self, start=0, end=0):
276                 if self.children is None:
277                         self.children = []
278                         res = self._db.getAllAlbums()
279                         items = self._get_data(res)
280                         for item in items:
281                                 self.add_child(Album(self._db, item, self))
282                 return DBContainer.get_children(self, start, end)
283
284         def get_item(self):
285                 if self.item is None:
286                         self.item = DIDLLite.Music(id=self.get_id(), parentID=self.parent.get_id(), title=self.name, restricted=True)
287                         self._set_item_defaults(searchClass="object.item.audioItem")
288                 return self.item
289
290 class Track(DBContainer):
291         schemaVersion = 1
292
293         def __init__(self, db, item, parent, combinedTitle=False):
294                 self._db_item = item
295                 artist, album, title, size, date, duration, genre, coverid = item[eMediaDatabase.FIELD_ARTIST], item[eMediaDatabase.FIELD_ALBUM], item[eMediaDatabase.FIELD_TITLE], item[eMediaDatabase.FIELD_SIZE], item[eMediaDatabase.FIELD_DATE], item[eMediaDatabase.FIELD_DURATION], item[eMediaDatabase.FIELD_GENRE], int(item[eMediaDatabase.FIELD_COVER_ART_ID])
296                 self.artist = convertString(artist)
297                 self.title = convertString(title)
298                 if combinedTitle:
299                         self.title = "%s - %s" %(self.artist, self.title)
300                 self.album = convertString(album)
301                 self.coverid = coverid
302                 self.size = convertString(size)
303                 self.date = convertString(date)
304                 self.duration = int(duration)
305                 self.genre = genre
306
307                 DBContainer.__init__(self, db, self.title, parent)
308                 self.location = "%s/%s" % (item[eMediaDatabase.FIELD_PATH], item[eMediaDatabase.FIELD_FILENAME])
309
310         def get_children(self, start=0, request_count=0):
311                 return []
312
313         def get_item(self):
314                 if self.item is None:
315                         self.item = DIDLLite.MusicTrack(self.get_id(), self.parent.get_id(), self.name, restricted=True)
316                         self._set_item_defaults()
317                         self.item.artist = self.artist
318                         self.item.creator = self.artist
319                         self.item.title = self.title
320                         self.item.album = self.album
321                         self.item.description = self.album
322                         self.item.date = self.date
323                         self.item.genre = self.genre
324                         self.item.restricted = True
325                         if self.coverid:
326                                 self.item.albumArtURI = self.store.getCoverArtUri(self.coverid)
327                         codec = self._db_item['codec']
328                         self._set_item_resources(codec, size=self.size, duration=self.duration)
329                 return self.item
330
331 class VideoContainer(DBContainer):
332         schemaVersion = 1
333         mimetype = 'directory'
334
335         def get_children(self, start=0, end=0):
336                 if self.children is None:
337                         self.children = []
338                         res = self._get_res()
339                         items = self._get_data(res)
340                         for item in items:
341                                 self.add_child(Video(self._db, item, self))
342                 return DBContainer.get_children(self, start, end)
343
344         def _get_res(self):
345                 return []
346
347         def get_item(self):
348                 if self.item is None:
349                         self.item = DIDLLite.Container(id=self.get_id(), parentID=self.parent.get_id(), title=self.name, restricted=True)
350                         self._set_item_defaults(searchClass="object.item.videoItem")
351                 return self.item
352
353 class VideoRecordings(VideoContainer):
354         def _get_res(self):
355                 return self._db.getAllRecordings()
356
357 class VideoUnseen(VideoContainer):
358         def _get_res(self):
359                 return self._db.query("SELECT * from video WHERE lastplaypos=?;", StringList(["0"]))
360
361 class VideoHD(VideoContainer):
362         def _get_res(self):
363                 return self._db.query("SELECT * from video WHERE hd=?;", StringList(["1"]))
364
365 class VideoSD(VideoContainer):
366         def _get_res(self):
367                 return self._db.query("SELECT * from video WHERE hd=?;", StringList(["0"]))
368
369 class VideoAll(VideoContainer):
370         def _get_res(self):
371                 return self._db.getAllVideos()
372
373 class Video(DBContainer):
374         schemaVersion = 1
375
376         def __init__(self, db, item, parent):
377                 self._db_item = item
378                 name, size, duration = item[eMediaDatabase.FIELD_TITLE], item[eMediaDatabase.FIELD_SIZE], item[eMediaDatabase.FIELD_DURATION]
379                 DBContainer.__init__(self, db, name, parent)
380                 self.location = "%s/%s" % (item[eMediaDatabase.FIELD_PATH], item[eMediaDatabase.FIELD_FILENAME])
381                 self.size = size
382                 self.duration = int(duration)
383
384         def get_children(self, start=0, request_count=0):
385                 return []
386
387         def get_item(self):
388                 if self.item is None:
389                         self.item = DIDLLite.Movie(self.get_id(), self.parent.get_id(), self.name, restricted=True)
390                         self._set_item_defaults(searchClass="object.item.videoItem")
391                         self.item.title = self.name
392                         self._default_mime = "video/mpeg"
393                         codec = self._db_item['codec']
394                         self._set_item_resources(codec, self.size, self.duration, resolution="720x576") #FIXME resolution is hardcoded
395                 return self.item
396
397 class DVBServiceList(BaseContainer):
398         def __init__(self, parent, title, ref):
399                 BaseContainer.__init__(self, parent, title)
400                 self.service_number = 0
401                 self.item = None
402                 self.location = ""
403                 self.children = None
404                 self.ref = ref
405                 self.sorted = True
406                 def childs_sort(x,y):
407                         return 1
408                 self.sorting_method = childs_sort
409
410         def get_service_number(self):
411                 return self.service_number
412
413         def get_item(self):
414                 if self.item == None:
415                         self.item = DIDLLite.Container(self.get_id(), self.parent.get_id(), self.name, restricted=True)
416                         self._set_item_defaults(searchClass="object.item.videoItem")
417                 return self.item
418
419         def get_children(self, start=0, end=0):
420                 if self.children is None:
421                         self.children = []
422                         self._init_services(self.ref)
423                 return BaseContainer.get_children(self, start, end)
424
425         def _get_next_service_nr(self):
426                 self.service_number += 1
427                 return self.service_number
428
429         def _gen_child(self, ref, name):
430                 return DVBServiceList(self, name, ref)
431
432         def _init_services(self, ref):
433                 self.info(ref)
434                 servicelist = None
435                 def get_servicelist(ref):
436                         servicelist.root = ref
437                 if ref:
438                         ref = eServiceReference(ref)
439                         if not ref.valid():
440                                 self.warning("Invalid ref %s" % ref)
441                                 return []
442                 else:
443                         self.warning("Missing ref!")
444
445                 servicelist = ServiceList(ref, command_func=get_servicelist, validate_commands=False)
446                 services = servicelist.getServicesAsList()
447                 for ref, name in services:
448                         if ref.startswith("1:64"): #skip markers
449                                 continue
450                         child = self._gen_child(ref, name)
451                         self.add_child(child)
452
453 class DVBService(DVBServiceList):
454         def __init__(self, parent, title, ref, is_radio=False):
455                 DVBServiceList.__init__(self, parent, title, ref)
456                 self.location = None
457                 self.streaminghost = None
458
459         def get_service_number(self):
460                 return self.service_number
461
462         def get_path(self):
463                 if self.streaminghost is None:
464                         self.streaminghost = self.store.server.coherence.hostname
465                 if self.location is None:
466                         self.location = 'http://' + self.streaminghost + ':8001/' + self.ref
467                 return self.location
468
469         def get_item(self):
470                 if self.item == None:
471                         self.item = DIDLLite.VideoBroadcast(self.get_id(), self.parent.get_id(), self.name, restricted=True)
472                         self._set_item_defaults(searchClass="object.item.videoItem")
473                         mimetype = "video/mpeg"
474                         additional_info = DLNA.getParams(mimetype)
475                         res = DIDLLite.Resource(self.get_path(), 'http-get:*:%s:%s' %(mimetype, additional_info))
476                         res.size = None
477                         self.item.res.append(res)
478                 return self.item
479
480         def get_children(self, start=0, end=0):
481                 return []
482
483 class Favorite(DVBServiceList):
484         def _gen_child(self, ref, name):
485                 return DVBService(self, name, ref)
486
487 class Favorites(DVBServiceList):
488         def _gen_child(self, ref, name):
489                 return Favorite(self, name, ref)
490
491 class Provider(DVBServiceList):
492         def _gen_child(self, ref, name):
493                 return DVBService(self, name, ref)
494
495 class ProviderList(DVBServiceList):
496         def _gen_child(self, ref, name):
497                 return Provider(self, name, ref)
498
499 from WebCoverResource import CoverRoot
500
501 class DreamboxMediaStore(AbstractBackendStore):
502         implements = ['MediaServer']
503         logCategory = 'dreambox_media_store'
504
505         def __init__(self, server, *args, **kwargs):
506                 AbstractBackendStore.__init__(self, server, **kwargs)
507                 self._db = eMediaDatabase.getInstance()
508
509                 self.next_id = 1000
510                 self.name = kwargs.get('name', 'Dreambox Mediaserver')
511                 # streaminghost is the ip address of the dreambox machine, defaults to localhost
512                 self.streaminghost = kwargs.get('streaminghost', self.server.coherence.hostname)
513
514                 self.refresh = float(kwargs.get('refresh', 1)) * 60
515                 self.init_root()
516                 self.init_completed()
517
518                 self._cover_root = None
519
520                 #Samsung TVs are special...
521 #               self._X_FeatureList = """&lt;Features xmlns=\"urn:schemas-upnp-org:av:avs\""
522 #               " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
523 #               " xsi:schemaLocation=\"urn:schemas-upnp-org:av:avs http://www.upnp.org/schemas/av/avs.xsd\"&gt;"
524 #               " &lt;Feature name=\"samsung.com_BASICVIEW\" version=\"1\"&gt;"
525 #                "&lt;container id=\"1\" type=\"object.item.audioItem\"/&gt;"
526 #                "&lt;container id=\"2\" type=\"object.item.videoItem\"/&gt;"
527 #                "&lt;container id=\"3\" type=\"object.item.imageItem\"/&gt;&lt;/Features&gt;"""
528
529         def getCoverArtUri(self, cover_id):
530                 return "%s/cover/%s" %(self.server.urlbase, cover_id)
531
532         def init_cover_root(self):
533                 if not self._cover_root:
534                         self._cover_root = self.server.web_resource.putChild("cover", CoverRoot())
535
536         def init_root(self):
537                 root = RootContainer(None, -1)
538                 self.set_root_item(root)
539
540                 #AUDIO
541                 if config.plugins.mediaserver.share_audio.value:
542                         self._audio = RootContainer(root, "Audio")
543                         root.add_child(self._audio, ROOT_CONTAINER_ID)
544
545                         self._artists_id = self._audio.add_child(
546                                         Artists(self._db, _("Artists"), self._audio)
547                                 )
548                         self._albums_id = self._audio.add_child(Albums(
549                                         self._db, _("Albums"), self._audio)
550                                 )
551                         self._album_artists_id = self._audio.add_child(
552                                         AlbumArtists(self._db, _("Album Artists"), self._audio)
553                                 )
554                         self._audio_all_id = self._audio.add_child(
555                                         AudioAll(self._db, _("All"), self._audio)
556                                 )
557
558                 #VIDEO
559                 if config.plugins.mediaserver.share_video.value:
560                         self._video = RootContainer(root, "Video")
561                         self._video_root_id = root.add_child(self._video)
562
563                         self._video_recordings_id = self._video.add_child(
564                                         VideoRecordings(self._db, _("Recordings"), self._video)
565                                 )
566                         self._video_unseen_id = self._video.add_child(
567                                         VideoUnseen(self._db, _("Unseen"), self._video)
568                                 )
569                         self._video_hd_id = self._video.add_child(
570                                         VideoHD(self._db, _("HD"), self._video)
571                                 )
572                         self._video_sd_id = self._video.add_child(
573                                         VideoSD(self._db, _("SD"), self._video)
574                                 )
575                         self._video_all_id = self._video.add_child(
576                                         VideoAll(self._db, _("All"), self._video)
577                                 )
578                 #DVB LIVE
579                 if config.plugins.mediaserver.share_live.value:
580                         self._live = RootContainer(root, "Livestreams (DVB)")
581                         self._live_root_id = root.add_child(self._live)
582                         #TV
583                         self._live_favorites_tv_id = self._live.add_child(
584                                         Favorites(self._live, _("Favorites (TV)"), "1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 195) || (type == 25) FROM BOUQUET \"bouquets.tv\" ORDER BY bouquet")
585                                 )
586                         self._live_provider_tv_id = self._live.add_child(
587                                         ProviderList(self._live, _("Provider (TV)"), "1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 195) || (type == 25) FROM PROVIDERS ORDER BY name")
588                                 )
589                         #RADIO
590                         self._live_favorites_radio_id = self._live.add_child(
591                                         Favorites(self._live, _("Favorites (Radio)"), "1:7:2:0:0:0:0:0:0:0:(type == 2)FROM BOUQUET \"bouquets.radio\" ORDER BY bouquet")
592                                 )
593                         self._live_provider_radio_id = self._live.add_child(
594                                         ProviderList(self._live, _("Provider (Radio)"), "1:7:2:0:0:0:0:0:0:0:(type == 2) FROM PROVIDERS ORDER BY name")
595                                 )
596
597                 root.sorted = True
598                 def childs_sort(x, y):
599                         return cmp(x.name, y.name)
600                 root.sorting_method = childs_sort
601
602         def upnp_GetSearchCapabilities(self, *args, **kwargs):
603                 self.init_cover_root()
604                 return {"SearchCaps" : "upnp:class,dc:title"}
605
606         def upnp_Browse(self, *args, **kwargs):
607                 self.init_cover_root()
608                 return self.server.content_directory_server.upnp_Browse(self, *args, **kwargs)
609
610         def upnp_Search(self, *args, **kwargs):
611                 self.init_cover_root()
612                 Log.d("%s" % (kwargs,))
613                 ContainerID = kwargs['ContainerID']
614                 Filter = kwargs['Filter']
615                 StartingIndex = int(kwargs['StartingIndex'])
616                 RequestedCount = int(kwargs['RequestedCount'])
617                 SortCriteria = kwargs['SortCriteria']
618                 SearchCriteria = kwargs['SearchCriteria']
619
620                 total = 0
621                 root_id = 0
622                 item = None
623                 items = []
624                 parent_container = None
625                 SearchCriteria = SearchCriteria.split(" ")
626                 if "derivedfrom" in SearchCriteria:
627                         if SearchCriteria[0] == "upnp:class":
628                                 Log.d("Searching by class! %s" % (SearchCriteria,))
629                                 if SearchCriteria[2].find(DIDLLite.AudioItem.upnp_class) >= 0:
630                                         parent_container = str(self._audio_all_id)
631                                 elif SearchCriteria[2].find(DIDLLite.VideoItem.upnp_class) >= 0:
632                                         parent_container = str(self._video_all_id)
633                                 Log.d(parent_container)
634                 if not parent_container:
635                         parent_container = str(ContainerID)
636                 didl = DIDLLite.DIDLElement(upnp_client=kwargs.get('X_UPnPClient', ''),
637                         parent_container=parent_container,
638                         transcoding=self.server.content_directory_server.transcoding)
639
640                 def build_response(tm):
641                         r = {'Result': didl.toString(), 'TotalMatches': tm,
642                                  'NumberReturned': didl.numItems()}
643
644                         if hasattr(item, 'update_id'):
645                                 r['UpdateID'] = item.update_id
646                         elif hasattr(self, 'update_id'):
647                                 r['UpdateID'] = self.update_id # FIXME
648                         else:
649                                 r['UpdateID'] = 0
650
651                         return r
652
653                 def got_error(r):
654                         return r
655
656                 def process_result(result, total=None, found_item=None):
657                         if result == None:
658                                 result = []
659
660                         l = []
661
662                         def process_items(result, tm):
663                                 if result == None:
664                                         result = []
665                                 for i in result:
666                                         if i[0] == True:
667                                                 didl.addItem(i[1])
668
669                                 return build_response(tm)
670
671                         for i in result:
672                                 d = defer.maybeDeferred(i.get_item)
673                                 l.append(d)
674
675                         if found_item != None:
676                                 def got_child_count(count):
677                                         dl = defer.DeferredList(l)
678                                         dl.addCallback(process_items, count)
679                                         return dl
680
681                                 d = defer.maybeDeferred(found_item.get_child_count)
682                                 d.addCallback(got_child_count)
683
684                                 return d
685                         elif total == None:
686                                 total = item.get_child_count()
687
688                         dl = defer.DeferredList(l)
689                         dl.addCallback(process_items, total)
690                         return dl
691
692                 def proceed(result):
693                         if kwargs.get('X_UPnPClient', '') == 'XBox' and hasattr(result, 'get_artist_all_tracks'):
694                                 d = defer.maybeDeferred(result.get_artist_all_tracks, StartingIndex, StartingIndex + RequestedCount)
695                         else:
696                                 d = defer.maybeDeferred(result.get_children, StartingIndex, StartingIndex + RequestedCount)
697                         d.addCallback(process_result, found_item=result)
698                         d.addErrback(got_error)
699                         return d
700
701                 try:
702                         root_id = parent_container
703                 except:
704                         pass
705
706                 wmc_mapping = getattr(self, "wmc_mapping", None)
707                 if kwargs.get('X_UPnPClient', '') == 'XBox':
708                         if wmc_mapping and wmc_mapping.has_key(parent_container):
709                                 """ fake a Windows Media Connect Server
710                                 """
711                                 root_id = wmc_mapping[parent_container]
712                                 if callable(root_id):
713                                         item = root_id()
714                                         if item is not None:
715                                                 if isinstance(item, list):
716                                                         total = len(item)
717                                                         if int(RequestedCount) == 0:
718                                                                 items = item[StartingIndex:]
719                                                         else:
720                                                                 items = item[StartingIndex:StartingIndex + RequestedCount]
721                                                         return process_result(items, total=total)
722                                                 else:
723                                                         if isinstance(item, defer.Deferred):
724                                                                 item.addCallback(proceed)
725                                                                 return item
726                                                         else:
727                                                                 return proceed(item)
728
729                                 item = self.get_by_id(root_id)
730                                 if item == None:
731                                         return process_result([], total=0)
732
733                                 if isinstance(item, defer.Deferred):
734                                         item.addCallback(proceed)
735                                         return item
736                                 else:
737                                         return proceed(item)
738
739
740                 item = self.get_by_id(root_id)
741                 Log.w(item)
742                 if item == None:
743                         Log.w(701)
744                         return failure.Failure(errorCode(701))
745
746                 if isinstance(item, defer.Deferred):
747                         item.addCallback(proceed)
748                         return item
749                 else:
750                         return proceed(item)
751
752         def upnp_init(self):
753                 if self.server:
754                         self.server.connection_manager_server.set_variable(0, 'SourceProtocolInfo', [
755                                         'http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN',
756                                         'http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM',
757                                         'http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED',
758                                         'http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG',
759                                         'http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_HD_50_AC3_ISO',
760                                         'http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_HD_60_AC3_ISO',
761                                         'http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_HP_HD_AC3_ISO',
762                                         'http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5_ISO',
763                                         'http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_HD_AC3_ISO',
764                                         'http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3_ISO',
765                                         'http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5_ISO',
766                                         'http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_SD_AC3_ISO',
767                                         'http-get:*:video/mpeg:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3_ISO',
768                                         'http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC',
769                                         'http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL',
770                                         'http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_HD_NA_ISO',
771                                         'http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_NA_ISO',
772                                         'http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_TS_SD_EU_ISO',
773                                         'http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1',
774                                         'http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AAC_MULT5',
775                                         'http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_SD_AC3',
776                                         'http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_BL_CIF15_AAC_520',
777                                         'http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_BL_CIF30_AAC_940',
778                                         'http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_BL_L31_HD_AAC',
779                                         'http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_BL_L32_HD_AAC',
780                                         'http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_BL_L3L_SD_AAC',
781                                         'http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_HP_HD_AAC',
782                                         'http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_HD_1080i_AAC',
783                                         'http-get:*:video/mp4:DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC',
784                                         'http-get:*:video/mp4:DLNA.ORG_PN=MPEG4_P2_MP4_ASP_AAC',
785                                         'http-get:*:video/mp4:DLNA.ORG_PN=MPEG4_P2_MP4_SP_VGA_AAC',
786                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_50_AC3',
787                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_50_AC3_T',
788                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_60_AC3',
789                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HD_60_AC3_T',
790                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_HP_HD_AC3_T',
791                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5',
792                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_AAC_MULT5_T',
793                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_AC3',
794                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_AC3_T',
795                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3',
796                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_HD_MPEG1_L3_T',
797                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5',
798                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_AAC_MULT5_T',
799                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_AC3',
800                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_AC3_T',
801                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3',
802                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=AVC_TS_MP_SD_MPEG1_L3_T',
803                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_HD_NA',
804                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_HD_NA_T',
805                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU',
806                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_EU_T',
807                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA',
808                                         'http-get:*:video/vnd.dlna.mpeg-tts:DLNA.ORG_PN=MPEG_TS_SD_NA_T',
809                                         'http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVSPLL_BASE',
810                                         'http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVSPML_BASE',
811                                         'http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVSPML_MP3',
812                                         'http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE',
813                                         'http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL',
814                                         'http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO',
815                                         'http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL',
816                                         'http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO',
817                                         'http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AAC',
818                                         'http-get:*:video/3gpp:DLNA.ORG_PN=MPEG4_P2_3GPP_SP_L0B_AMR',
819                                         'http-get:*:audio/mpeg:DLNA.ORG_PN=MP3',
820                                         'http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMABASE',
821                                         'http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAFULL',
822                                         'http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAPRO',
823                                         'http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMALSL',
824                                         'http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMALSL_MULT5',
825                                         'http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO_320',
826                                         'http-get:*:audio/3gpp:DLNA.ORG_PN=AAC_ISO_320',
827                                         'http-get:*:audio/mp4:DLNA.ORG_PN=AAC_ISO',
828                                         'http-get:*:audio/mp4:DLNA.ORG_PN=AAC_MULT5_ISO',
829                                         'http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM',
830                                         'http-get:*:image/jpeg:*',
831                                         'http-get:*:video/avi:*',
832                                         'http-get:*:video/divx:*',
833                                         'http-get:*:video/x-matroska:*',
834                                         'http-get:*:video/mpeg:*',
835                                         'http-get:*:video/mp4:*',
836                                         'http-get:*:video/x-ms-wmv:*',
837                                         'http-get:*:video/x-msvideo:*',
838                                         'http-get:*:video/x-flv:*',
839                                         'http-get:*:video/x-tivo-mpeg:*',
840                                         'http-get:*:video/quicktime:*',
841                                         'http-get:*:audio/mp4:*',
842                                         'http-get:*:audio/x-wav:*',
843                                         'http-get:*:audio/x-flac:*',
844                                         'http-get:*:application/ogg:*'
845                                 ])
846
847                         #Samsung TVs are special...
848                         self.server.content_directory_server.register_vendor_variable(
849                                 'X_FeatureList',
850                                 evented='no',
851                                 data_type='string',
852                                 default_value="")
853
854                         self.server.content_directory_server.register_vendor_action(
855                                 'X_GetFeatureList', 'optional',
856                                 (('FeatureList', 'out', 'X_FeatureList'),),
857                                 needs_callback=False)
858
859         def upnp_X_GetFeatureList(self,**kwargs):
860                 Log.w()
861                 attrib = {
862                                 "xmlns" : "urn:schemas-upnp-org:av:avs",
863                                 "xmlns:xsi" : "http://www.w3.org/2001/XMLSchema-instance",
864                                 "xsi:schemaLocation" : "urn:schemas-upnp-org:av:avs http://www.upnp.org/schemas/av/avs.xsd"
865                         }
866                 features = ET.Element("Features")
867                 features.attrib.update(attrib)
868
869                 attrib = {
870                                 "name" : "samsung.com_BASICVIEW",
871                                 "version" : "1"
872                         }
873                 feature = ET.SubElement(features, "Feature")
874                 feature.attrib.update(attrib)
875                 #audio/video container id definition
876                 tag = ET.SubElement(feature, "container")
877                 tag.attrib.update({ "type": DIDLLite.AudioItem.upnp_class, "id" : str(self._audio.get_id()) })
878                 tag = ET.SubElement(feature, "container")
879                 tag.attrib.update({ "type": DIDLLite.VideoItem.upnp_class, "id" : str(self._video.get_id()) })
880                 return {"FeatureList" : ET.tostring(features, "utf-8")}
881
882 def restartMediaServer(name, uuid, **kwargs):
883         cp = resourcemanager.getResource("UPnPControlPoint")
884         if cp:
885                 removeUPnPDevice(uuid, cp)
886                 return cp.registerServer(DreamboxMediaStore, name=name, uuid=uuid, **kwargs)
887         return None
888