Coverage for coherence/upnp/core/DIDLLite.py : 65%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# Licensed under the MIT license # http://opensource.org/licenses/mit-license.php
# Copyright 2005, Tim Potter <tpot@samba.org> # Copyright 2006, Frank Scholz <coherence@beebits.net>
TODO:
- use more XPath expressions in fromElement() methods
"""
return tag
""" checks for type audio, expects a mimetype or an UPnP protocolInfo """ test = mimetype.split(':') if len(test) == 4: mimetype = test[2] if mimetype == 'application/ogg': return True if mimetype.startswith('audio/'): return True return False
""" checks for type video, expects a mimetype or an UPnP protocolInfo """ test = mimetype.split(':') if len(test) == 4: mimetype = test[2] if mimetype.startswith('video/'): return True return False
""" a list of resources, always sorted after an append """
""" we want the following order http-get is always at the beginning rtsp-rtp-udp the second anything else after that """ return 1 return -1
return 0 return 1 return -1
result = [] if not isinstance(local_protocol_infos, list): local_protocol_infos = [local_protocol_infos] for res in self: if res.importUri is not None: continue # print "res", res.protocolInfo, res.data remote_protocol, remote_network, remote_content_format, _ = \ res.protocolInfo.split(':') # print("remote", remote_protocol, # remote_network,remote_content_format) if (protocol_type is not None and remote_protocol.lower() != protocol_type.lower()): continue for protocol_info in local_protocol_infos: local_protocol, local_network, local_content_format, _ = \ protocol_info.split(':') # print("local", local_protocol, # local_network,local_content_format) if (remote_protocol == local_protocol or remote_protocol == '*' or local_protocol == '*') and \ (remote_network == local_network or remote_network == '*' or local_network == '*') and \ (remote_content_format.startswith( local_content_format) or remote_content_format == '*' or local_content_format == '*'): result.append(res) return result
return Item return MusicAlbum else: return Photo return MusicTrack if mimetype.find('video/') == 0: return VideoItem if mimetype == 'application/ogg': if sub == 'music': # FIXME: this is stupid return MusicTrack return AudioItem if mimetype == 'application/x-flac': if sub == 'music': # FIXME: this is stupid return MusicTrack return AudioItem return None
'DLNA.ORG_PS=1', # play speed parameter 'DLNA.ORG_CI=0', # transcoded parameter 'DLNA.ORG_FLAGS=01100000000000000000000000000000']
additional_info = ['DLNA.ORG_PN=WMABASE'] + simple_dlna_tags dlna_tags = simple_dlna_tags[:] dlna_tags[3] = 'DLNA.ORG_FLAGS=00900000000000000000000000000000' additional_info = ['DLNA.ORG_PN=PNG_LRG'] + dlna_tags additional_info = ['DLNA.ORG_PN=MPEG_TS_PAL'] + simple_dlna_tags content_format = 'video/mpeg' ['DLNA.ORG_PN=AVC_TS_BL_CIF15_AAC'] + simple_dlna_tags # additional_info = ';'.join( # ['DLNA.ORG_PN=MPEG4_P2_MP4_SP_AAC']+simple_dlna_tags) additional_info = ['DLNA.ORG_PN=WMV_BASE'] + simple_dlna_tags additional_info = simple_dlna_tags
i = 0 for part in additional_info: if part.startswith('DLNA.ORG_FLAGS'): _, bits = part.split('=') bits = int(bits, 16) bits |= 0x10000000000000000000000000000000 additional_info[i] = 'DLNA.ORG_FLAGS=%.32x' % bits break i += 1
"""An object representing a resource."""
data = str(data)
self.protocolInfo.split(':') network, content_format, build_dlna_additional_info( content_format)]) elif additional_info == '#': self.protocolInfo = ':'.join([protocol, network, content_format, '*'])
self.protocolInfo.split(':') """ we don't need the DLNA tags there, and maybe they irritate these poor things anyway """ if content_format.startswith('video/'): additional_info = '*'
a_list.remove(part) break
self.protocolInfo.split(':') content_format = 'video/avi' content_format = 'audio/wav' upnp_client=kwargs.get('upnp_client', '')) (protocol, network, content_format, additional_info)) else: self.protocolInfo.split(':') content_format = 'video/divx' upnp_client=kwargs.get('upnp_client', '')) (protocol, network, content_format, additional_info))
root.attrib['bitrate'] = str(self.bitrate)
root.attrib['duration'] = self.duration
root.attrib['nrAudioChannels'] = self.nrAudioChannels
root.attrib['resolution'] = self.resolution
root.attrib['importUri'] = self.importUri
return etree.tostring(self.toElement(**kwargs), encoding='utf-8')
def fromString(cls, _string):
protocol, network, content_format, additional_info = \ self.protocolInfo.split(':') dlna_tags = simple_dlna_tags[:] # dlna_tags[1] = 'DLNA.ORG_OP=00' dlna_tags[2] = 'DLNA.ORG_CI=1' if format == 'mp3': if content_format == 'audio/mpeg': return None content_format = 'audio/mpeg' dlna_pn = 'DLNA.ORG_PN=MP3' elif format == 'lpcm': dlna_pn = 'DLNA.ORG_PN=LPCM' content_format = 'audio/L16;rate=44100;channels=2' elif format == 'mpegts': if content_format == 'video/mpeg': return None # 'DLNA.ORG_PN=MPEG_TS_SD_EU' # FIXME - don't forget HD dlna_pn = 'DLNA.ORG_PN=MPEG_PS_PAL' content_format = 'video/mpeg' else: return None
additional_info = ';'.join([dlna_pn] + dlna_tags) new_protocol_info = ':'.join( (protocol, network, content_format, additional_info))
new_res = Resource(self.data + '/transcoded/%s' % format, new_protocol_info) new_res.size = None new_res.duration = self.duration new_res.resolution = self.resolution return new_res
"""An object representing a DLNA playcontainer resource."""
sid='urn:upnp-org:serviceId:ContentDirectory', cid=None, fid=None, fii=0, sc='', md=0, protocol_info=None):
Resource.__init__(self) if cid is None: raise AttributeError('missing Container Id') if fid is None: raise AttributeError('missing first Child Id') self.protocolInfo = protocol_info
args = ['sid=' + urllib.parse.quote(sid), 'cid=' + urllib.parse.quote(str(cid)), 'fid=' + urllib.parse.quote(str(fid)), 'fii=' + urllib.parse.quote(str(fii)), 'sc=' + urllib.parse.quote(''), 'md=' + urllib.parse.quote(str(0))]
self.data = 'dlna-playcontainer://' + \ urllib.parse.quote(str(udn)) \ + '?' + '&'.join(args)
if self.protocolInfo is None: self.protocolInfo = 'http-get:*:*:*'
"""The root class of the entire content directory class heirachy."""
creator=None):
return self
self.title
# if kwargs.get('requested_id') != '0' and # kwargs.get('requested_id') != root.attrib['id']: root.attrib['refID'], root.attrib['id'], root.attrib['parentID']) else: self.id, root.attrib['id'], root.attrib['parentID']) kwargs.get('parent_container') != root.attrib['parentID']): root.attrib['refID'] = root.attrib['id'] (root.attrib['id'], kwargs.get('parent_container'))) self.info( "Changing ID from %r to %r, " "with parentID from %r to %r", root.attrib['refID'], root.attrib['id'], self.parentID, root.attrib['parentID']) else: "Changing ID from %r to %r, " "with parentID from %r to %r", self.id, root.attrib['id'], self.parentID, root.attrib['parentID'])
root, qname('class', xml_constants.UPNP_NS)).text = self.upnp_class
None) is not None and u.text.startswith( 'object.container'): if kwargs.get('parent_container') in ('14', '15', '16'): u.text = 'object.container.storageFolder'
root.attrib['restricted'] = '1' else:
etree.SubElement(root, qname( 'creator', xml_constants.DC_NS)).text = self.creator
etree.SubElement(root, qname( 'writeStatus', xml_constants.UPNP_NS)).text = self.writeStatus
'date', xml_constants.DC_NS)).text = self.date.isoformat() else: etree.SubElement(root, qname( 'date', xml_constants.DC_NS)).text = self.date else: 'date', xml_constants.DC_NS)).text = utils.datefaker().isoformat()
root, qname('albumArtURI', xml_constants.UPNP_NS)) 'profileID', xml_constants.DLNA_NS)] = 'JPEG_TN'
root, qname( 'artist', xml_constants.UPNP_NS)).text = self.artist
etree.SubElement( root, qname( 'genre', xml_constants.UPNP_NS)).text = self.genre
for genre in self.genres: etree.SubElement( root, qname( 'genre', xml_constants.UPNP_NS)).text = genre
etree.SubElement( root, qname('originalTrackNumber', xml_constants.UPNP_NS)).text = \ str(self.originalTrackNumber)
etree.SubElement( root, qname('description', xml_constants.DC_NS)).text = \ self.description
etree.SubElement( root, qname('longDescription', xml_constants.UPNP_NS)).text = \ self.longDescription
etree.SubElement( root, qname('server_uuid', xml_constants.UPNP_NS)).text = \ self.server_uuid
return etree.tostring(self.toElement(**kwargs), encoding='utf-8').decode('utf-8')
""" TODO: * creator * writeStatus """
1, 'true', 'True', '1', 'yes', 'Yes']: self.restricted = True else:
self.originalTrackNumber = int(child.text) self.description = child.text self.longDescription = child.text if self.genre is not None: if self.genres is None: self.genres = [self.genre, ] self.genres.append(child.text) self.genre = child.text
self.album = child.text self.server_uuid = child.text
def fromString(cls, data):
"""A class used to represent atomic (non-container) content objects."""
etree.SubElement( root, qname('director', xml_constants.UPNP_NS)).text = \ self.director
etree.SubElement(root, 'refID').text = self.refID
for actor in self.actors: etree.SubElement( root, qname('actor', xml_constants.DC_NS)).text = actor
etree.SubElement( root, qname('language', xml_constants.DC_NS)).text = \ self.language
res = self.res.get_matching(['*:*:*:*'], protocol_type='http-get') if len(res) > 0 and is_audio(res[0].protocolInfo): old_res = res[0] if kwargs.get('upnp_client', '') == 'XBox': transcoded_res = old_res.transcoded('mp3') if transcoded_res is not None: root.append(transcoded_res.toElement(**kwargs)) else: root.append(old_res.toElement(**kwargs)) else: for res in self.res: root.append(res.toElement(**kwargs)) transcoded_res = old_res.transcoded('lpcm') if transcoded_res is not None: root.append(transcoded_res.toElement(**kwargs)) elif len(res) > 0 and is_video(res[0].protocolInfo): old_res = res[0] for res in self.res: root.append(res.toElement(**kwargs)) transcoded_res = old_res.transcoded('mpegts') if transcoded_res is not None: root.append(transcoded_res.toElement(**kwargs)) else: for res in self.res: root.append(res.toElement(**kwargs)) else:
self.refID = child.text self.director = child.text
root = Item.toElement(self, **kwargs)
if self.rating is not None: etree.SubElement( root, qname('rating', xml_constants.UPNP_NS)).text = \ str(self.rating)
if self.storageMedium is not None: etree.SubElement( root, qname('storageMedium', xml_constants.UPNP_NS)).text = \ self.storageMedium
if self.publisher is not None: etree.SubElement( root, qname('publisher', xml_constants.DC_NS)).text = \ self.publisher
if self.rights is not None: etree.SubElement( root, qname('rights', xml_constants.DC_NS)).text = self.rights
return root
root = ImageItem.toElement(self, **kwargs) if self.album is not None: etree.SubElement( root, qname('album', xml_constants.UPNP_NS)).text = self.album return root
"""A piece of content that when rendered generates some audio."""
'language', 'relation', 'rights', 'albumArtURI']
etree.SubElement( root, qname('publisher', xml_constants.DC_NS)).text = \ self.publisher
etree.SubElement( root, qname('language', xml_constants.DC_NS)).text = \ self.language
etree.SubElement( root, qname('relation', xml_constants.DC_NS)).text = \ self.relation
etree.SubElement( root, qname('rights', xml_constants.DC_NS)).text = self.rights
setattr(self, tag, val)
"""A discrete piece of audio that should be interpreted as music."""
etree.SubElement( root, qname('album', xml_constants.UPNP_NS)).text = self.album
etree.SubElement( root, qname('playlist', xml_constants.UPNP_NS)).text = \ self.playlist
etree.SubElement( root, qname('storageMedium', xml_constants.UPNP_NS)).text = \ self.storageMedium
etree.SubElement( root, qname('contributor', xml_constants.DC_NS)).text = \ self.contributor
rating=xml_constants.UPNP_NS, publisher=xml_constants.DC_NS, relation=xml_constants.DC_NS)
root = Item.toElement(self, **kwargs)
for attr_name, ns in self.valid_attrs.items(): value = getattr(self, attr_name, None) if value: self.debug("Setting value {%s}%s=%s", ns, attr_name, value) etree.SubElement(root, qname(attr_name, ns)).text = value
return root
Item.fromElement(self, elt) for child in elt.getchildren(): tag = child.tag val = child.text if tag in list(self.valid_attrs.keys()): setattr(self, tag, val)
VideoItem.__init__(self, *args, **kwargs) self.valid_attrs.update( dict( storageMedium=xml_constants.UPNP_NS, DVDRegionCode=xml_constants.UPNP_NS, channelName=xml_constants.UPNP_NS, scheduledStartTime=xml_constants.UPNP_NS, sccheduledEndTime=xml_constants.UPNP_NS))
"""An object that can contain other objects."""
restricted=False, creator=None):
etree.SubElement( root, qname('createclass', xml_constants.UPNP_NS)).text = \ self.createClass
self.searchClass = [self.searchClass] sc = etree.SubElement( root, qname('searchClass', xml_constants.UPNP_NS)) sc.attrib['includeDerived'] = '1' sc.text = i
root.attrib['searchable'] = '1' else:
root.append(res.toElement(**kwargs))
# self.searchable = int(elt.attrib.get('searchable','0')) elt.attrib.get('searchable', '0') in [1, 'True', 'true', '1'] self.createClass = child.text self.searchClass.append(child.text)
parent_container=None, requested_id=None, transcoding=False):
'DIDL-Lite', nsmap={None: xml_constants.DIDLLITE_NS, 'dc': xml_constants.DC_NS, 'upnp': xml_constants.UPNP_NS})
e = Container(id, parent_id, title, restricted, creator='') self.element.append(e.toElement())
upnp_client=self.upnp_client, parent_container=self.parent_container, requested_id=self.requested_id, transcoding=self.transcoding))
self.element.clear() for item in self._items: self.element.append(item.toElement( upnp_client=self.upnp_client, parent_container=self.parent_container, requested_id=self.requested_id, transcoding=self.transcoding))
""" sigh - having that optional preamble here breaks some of the older ContentDirectoryClients """ pretty_print=True).decode('utf-8')
def fromString(cls, data): '{%s}class' % 'urn:schemas-upnp-org:metadata-1-0/upnp/')
'object.item': Item, 'object.item.imageItem': ImageItem, 'object.item.imageItem.photo': Photo, 'object.item.audioItem': AudioItem, 'object.item.audioItem.musicTrack': MusicTrack, 'object.item.audioItem.audioBroadcast': AudioBroadcast, 'object.item.audioItem.audioBook': AudioBook, 'object.item.videoItem': VideoItem, 'object.item.videoItem.movie': Movie, 'object.item.videoItem.videoBroadcast': VideoBroadcast, 'object.item.videoItem.musicVideoClip': MusicVideoClip, 'object.item.playlistItem': PlaylistItem, 'object.item.textItem': TextItem, 'object.container': Container, 'object.container.person': Person, 'object.container.person.musicArtist': MusicArtist, 'object.container.playlistContainer': PlaylistContainer, 'object.container.album': Album, 'object.container.album.musicAlbum': MusicAlbum, 'object.container.album.photoAlbum': PhotoAlbum, 'object.container.genre': Genre, 'object.container.genre.musicGenre': MusicGenre, 'object.container.genre.movieGenre': MovieGenre, 'object.container.storageSystem': StorageSystem, 'object.container.storageVolume': StorageVolume, 'object.container.storageFolder': StorageFolder, }
res = Resources() res.append(Resource('1', 'file:*:*:*')) res.append(Resource('2', 'rtsp-rtp-udp:*:*:*')) res.append(Resource('3', None)) res.append(Resource('4', 'internal:*:*:*')) res.append(Resource('5', 'http-get:*:*:*')) res.append(Resource('6', 'something:*:*:*')) res.append(Resource('7', 'http-get:*:*:*'))
for r in res: print(r.data, r.protocolInfo) |