Esempio n. 1
0
 def _notify(self, statevars):
     # create the request body
     propset = Element("e:propertyset")
     propset.attrib['xmlns:e'] = "urn:schemas-upnp-org:event-1-0"
     prop = SubElement(propset, "e:property")
     # add each evented statevar to the property set
     for statevar in statevars:
         if statevar.sendEvents:
             SubElement(prop, statevar.name).text = statevar.text_value
         else:
             raise Exception("StateVar '%s' is not evented" % statevar.name)
     postData = xmlprint(propset)
     logger.log_debug("NOTIFY property set:\n" + postData)
     # send the NOTIFY request to each callback
     for url,urlparts in self.callbacks:
         # set the NOTIFY headers
         headers = {
             'Host': urlparts.netloc,
             'Content-Type': MimeType('text', 'xml'),
             'NT': 'upnp:event',
             'NTS': 'upnp:propchange',
             'SID': self.id,
             'SEQ': self.seqid
             }
         #
         creator = protocol.ClientCreator(reactor, HTTPClientProtocol)
         request = ClientRequest("NOTIFY", urlparts.path, headers, postData)
         d = creator.connectTCP(urlparts.hostname, urlparts.port)
         d.addCallback(self._sendNotifyRequest, request)
         logger.log_debug("sending NOTIFY to %s" % url)
     self.seqid = self.seqid + 1
Esempio n. 2
0
 def _dispatchSoapRequest(self, request):
     try:
         try:
             envelope = XML(request.soap_data)
             body = envelope.find("{http://schemas.xmlsoap.org/soap/envelope/}Body")
             # determine UPnP action
             action = body.find("{%s}%s" % (request.soap_ns, request.soap_action))
             # look up the action in the service
             upnp_action = self.service._actions[request.soap_action]
             # build a list of the action arguments
             in_args = {}
             for arg in action:
                 in_args[arg.tag] = arg.text
             # execute the UPnP action
             logger.log_debug("executing %s#%s" % (self.service.serviceID, request.soap_action))
             out_args = upnp_action(request, self.service, in_args)
             # return the action response
             env = Element("s:Envelope")
             env.attrib['xmlns:s'] = "http://schemas.xmlsoap.org/soap/envelope/"
             env.attrib['s:encodingStyle'] = "http://schemas.xmlsoap.org/soap/encoding/"
             env.attrib['xmlns:i'] = "http://www.w3.org/1999/XMLSchema-instance"
             body = SubElement(env, "s:Body")
             resp = SubElement(body, "u:%sResponse" % request.soap_action)
             resp.attrib['xmlns:u'] = request.soap_ns
             for (name,type,value) in out_args:
                 arg = SubElement(resp, name)
                 arg.attrib["i:type"] = type
                 arg.text = value
             output = xmlprint(env)
             return HttpResponse(200, headers={'EXT': ''}, stream=output)
         except UPNPError, e:
             raise e
         except Exception, e:
             logger.log_error("caught unhandled exception: %s" % e)
             raise UPNPError(500, "Internal server error")
Esempio n. 3
0
 def getDescription(self, host, relativeUrls=False):
     root = Element("root")
     root.attrib["xmlns"] = "urn:schemas-upnp-org:device-1-0"
     version = SubElement(root, "specVersion")
     SubElement(version, "major").text = "1"
     SubElement(version, "minor").text = "0"
     device = SubElement(root, "device")
     SubElement(device, "deviceType").text = self.deviceType
     SubElement(device, "friendlyName").text = self.friendlyName
     SubElement(device, "manufacturer").text = self.manufacturer
     SubElement(device, "UDN").text = "uuid:%s" % self.UDN
     SubElement(device, "modelName").text = self.modelName
     if self.manufacturerURL:
         SubElement(device, "manufacturerURL").text = self.manufacturerURL
     if self.modelDescription:
         SubElement(device, "modelDescription").text = self.modelDescription
     if self.modelURL:
         SubElement(device, "modelURL").text = self.modelURL
     if self.modelNumber:
         SubElement(device, "modelNumber").text = self.modelNumber
     if self.serialNumber:
         SubElement(device, "serialNumber").text = self.serialNumber
     if relativeUrls:
         urlbase = ""
         SubElement(device, "URLBase").text = "http://%s" % host
     else:
         urlbase = "http://%s" % host
     svc_list = SubElement(device, "serviceList")
     for svc in self._services.values():
         service = SubElement(svc_list, "service")
         SubElement(service, "serviceType").text = svc.serviceType
         SubElement(service, "serviceId").text = svc.serviceID
         SubElement(service, "SCPDURL").text = "%s/%s/%s" % (
             urlbase,
             self.UDN.replace(":", "_"),
             svc.serviceID.replace(":", "_"),
         )
         SubElement(service, "controlURL").text = "%s/%s/%s/control" % (
             urlbase,
             self.UDN.replace(":", "_"),
             svc.serviceID.replace(":", "_"),
         )
         SubElement(service, "eventSubURL").text = "%s/%s/%s/event" % (
             urlbase,
             self.UDN.replace(":", "_"),
             svc.serviceID.replace(":", "_"),
         )
     return xmlprint(root)
Esempio n. 4
0
 def getDescription(self):
     scpd = Element("scpd")
     scpd.attrib['xmlns'] = 'urn:schemas-upnp-org:service-1-0'
     version = SubElement(scpd, "specVersion")
     SubElement(version, "major").text = "1"
     SubElement(version, "minor").text = "0"
     action_list = SubElement(scpd, "actionList")
     for action_name,upnp_action in self._actions.items():
         action = SubElement(action_list, "action")
         SubElement(action, "name").text = action_name
         arg_list = SubElement(action, "argumentList")
         all_args = upnp_action.in_args + upnp_action.out_args
         for upnp_arg in all_args:
             arg = SubElement(arg_list, "argument")
             SubElement(arg, "name").text = upnp_arg.name
             SubElement(arg, "direction").text = upnp_arg.direction
             SubElement(arg, "relatedStateVariable").text = upnp_arg.related.name
             if upnp_arg.retval:
                 SubElement(arg, "retval")
     var_list = SubElement(scpd, "serviceStateTable")
     for var_name,upnp_stateVar in self._stateVars.items():
         stateVar = SubElement(var_list, "stateVariable")
         if upnp_stateVar.sendEvents:
             stateVar.attrib['sendEvents'] = "yes"
         else:
             stateVar.attrib['sendEvents'] = "no"
         SubElement(stateVar, "name").text = var_name
         SubElement(stateVar, "dataType").text = upnp_stateVar.type
         #if not upnp_stateVar.text_value == None:
         #    SubElement(stateVar, "defaultValue").text = upnp_stateVar.text_value
         if not upnp_stateVar.allowedValueList == None:
             allowed_list = SubElement(stateVar, "allowedValueList")
             for allowed in upnp_stateVar.allowedValueList:
                 SubElement(allowed_list, "allowedValue").text = allowed
         if not upnp_stateVar.allowedMin == None and not upnp_stateVar.allowedMax == None:
             allowed_range = SubElement(stateVar, "allowedValueRange")
             SubElement(allowed_range, "minimum").text = str(upnp_stateVar.allowedMin)
             SubElement(allowed_range, "maximum").text = str(upnp_stateVar.allowedMax)
             if not upnp_stateVar.allowedStep == None:
                 SubElement(allowed_range, "step").text = str(upnp_stateVar.allowedStep)
     return xmlprint(scpd)
Esempio n. 5
0
 def Browse(self, request, objectID, browseFlag, filter, startingIndex, requestedCount, sortCriteria):
     # determine the host:port of content
     host = request.headers.getHeader('host').split(':',1)[0]
     port = CoreHttpConfig.HTTP_PORT
     # break up the objectID into segments.  objectIDs have the following form:
     # 0/<artist>/<album>/<song>
     segments = objectID.split('/')
     if len(segments) < 1 or segments[0] != '0':
         raise UPNPError(701, "ObjectID %i is invalid" % objectID)
     # generate the DIDL envelope
     didl = Element("DIDL-Lite")
     didl.attrib["xmlns"] = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"
     didl.attrib["xmlns:upnp"] = "urn:schemas-upnp-org:metadata-1-0/upnp/"
     didl.attrib["xmlns:dc"] = "http://purl.org/dc/elements/1.1/"
     # browse the metadata of one specific item
     if browseFlag == 'BrowseMetadata':
         if len(segments) == 1:
             container = SubElement(didl, 'container')
             container.attrib['id'] = objectID
             container.attrib['parentID'] = '-1'
             container.attrib['restricted'] = '1'
             container.attrib['childCount'] = '2'
             SubElement(container, 'dc:title').text = 'Media on Higgins'
             SubElement(container, 'upnp:class').text = 'object.container.storageFolder'
         elif len(segments) > 1:
             if segments[1] == 'music':
                 if len(segments) == 2:
                     container = SubElement(didl, 'container')
                     container.attrib['id'] = objectID
                     container.attrib['parentID'] = '0'
                     container.attrib['restricted'] = '1'
                     container.attrib['childCount'] = str(len(Artist.objects.all()))
                     SubElement(container, 'dc:title').text = 'Music'
                     SubElement(container, 'upnp:class').text = 'object.container.storageFolder'
                 elif len(segments) == 3:
                     artist = Artist.objects.get(id=int(segments[2]))
                     container = SubElement(didl, 'container')
                     container.attrib['id'] = objectID
                     container.attrib['parentID'] = '/'.join(segments[:1])
                     container.attrib['restricted'] = '1'
                     container.attrib['childCount'] = str(len(Album.objects.filter(artist=artist)))
                     SubElement(container, 'dc:title').text = str(artist.name)
                     SubElement(container, 'upnp:class').text = 'object.container.person.musicArtist'
                 elif len(segments) == 4:
                     album = Album.objects.get(id=int(segments[3]), artist=int(segments[2]))
                     container = SubElement(didl, 'container')
                     container.attrib['id'] = objectID
                     container.attrib['parentID'] = '/'.join(segments[:1])
                     container.attrib['restricted'] = '1'
                     container.attrib['childCount'] = str(len(Song.objects.filter(album=album)))
                     SubElement(container, 'dc:title').text = str(album.name)
                     SubElement(container, 'upnp:class').text = 'object.container.album.musicAlbum'
             if segments[1] == 'playlists':
                 if len(segments) == 2:
                     container = SubElement(didl, 'container')
                     container.attrib['id'] = objectID
                     container.attrib['parentID'] = '0'
                     container.attrib['restricted'] = '1'
                     container.attrib['childCount'] = str(len(Playlist.objects.all()))
                     SubElement(container, 'dc:title').text = 'Playlists'
                     SubElement(container, 'upnp:class').text = 'object.container.storageFolder'
                 elif len(segments) == 3:
                     playlist = Playlist.objects.get(id=int(segments[2]))
                     container = SubElement(didl, 'container')
                     container.attrib['id'] = objectID
                     container.attrib['parentID'] = '/'.join(segments[:1])
                     container.attrib['restricted'] = '1'
                     container.attrib['childCount'] = str(len(playlist))
                     SubElement(container, 'dc:title').text = str(playlist.name)
                     SubElement(container, 'upnp:class').text = 'object.container.playlistContainer'
         total_matches = 1
         number_returned = 1
     elif browseFlag == 'BrowseDirectChildren':
         def getMatches(startingIndex, requestedCount, qset):
             # don't return more than 100 items
             total_matches = len(qset)
             if requestedCount > 100 or requestedCount == 0:
                 requestedCount = 100
             if startingIndex >= total_matches:
                 raise UPNPError(402, "startingIndex %i is out of range" % startingIndex)
             if startingIndex + requestedCount > total_matches:
                 requestedCount = total_matches - startingIndex
             matches = qset[startingIndex:startingIndex + requestedCount]
             number_returned = len(matches)
             retval = (matches, total_matches, number_returned)
             logger.log_debug("getMatches: %s" % str(retval))
             return retval
         # determine the number of matches
         if len(segments) == 1:
             container = SubElement(didl, "container")
             container.attrib["id"] = '0/music'
             container.attrib["parentID"] = '0'
             container.attrib["restricted"] = "1"
             container.attrib['childCount'] = str(len(Album.objects.all()))
             SubElement(container, "upnp:class").text = "object.container.storageFolder"
             SubElement(container, "dc:title").text = 'Music'
             container = SubElement(didl, "container")
             container.attrib["id"] = '0/playlists'
             container.attrib["parentID"] = '0'
             container.attrib["restricted"] = "1"
             container.attrib['childCount'] = str(len(Playlist.objects.all()))
             SubElement(container, "upnp:class").text = "object.container.storageFolder"
             SubElement(container, "dc:title").text = 'Playlists'
             total_matches = 2
             number_returned = 2
         if len(segments) > 1:
             if segments[1] == 'music':
                 if len(segments) == 2:
                     qset = Artist.objects.all()
                     matches,total_matches,number_returned = getMatches(startingIndex, requestedCount, qset)
                     for artist in matches:
                         container = SubElement(didl, "container")
                         container.attrib["id"] = objectID + '/' + str(artist.id)
                         container.attrib["parentID"] = '/'.join(segments[:-1])
                         container.attrib["restricted"] = "1"
                         container.attrib['childCount'] = str(len(Album.objects.filter(artist=artist)))
                         SubElement(container, "upnp:class").text = "object.container.person.musicArtist"
                         SubElement(container, "dc:title").text = artist.name
                 elif len(segments) == 3:
                     qset = Album.objects.filter(artist=int(segments[2]))
                     matches,total_matches,number_returned = getMatches(startingIndex, requestedCount, qset)
                     for album in matches:
                         container = SubElement(didl, "container")
                         container.attrib["id"] = objectID + '/' + str(album.id)
                         container.attrib["parentID"] = '/'.join(segments[:-1])
                         container.attrib["restricted"] = "1"
                         container.attrib['childCount'] = str(len(Song.objects.filter(album=album)))
                         SubElement(container, "upnp:class").text = "object.container.album.musicAlbum"
                         SubElement(container, "dc:title").text = album.name
                 elif len(segments) == 4:
                     qset = Song.objects.filter(album=int(segments[3]))
                     matches,total_matches,number_returned = getMatches(startingIndex, requestedCount, qset)
                     for song in matches:
                         item = SubElement(didl, "item")
                         item.attrib["id"] = objectID + '/' + str(song.id)
                         item.attrib["parentID"] = '/'.join(segments[:-1])
                         item.attrib["restricted"] = "1"
                         SubElement(item, "upnp:class").text = "object.item.audioItem.musicTrack"
                         SubElement(item, "dc:title").text = song.name
                         SubElement(item, "upnp:artist").text = str(song.artist.name)
                         SubElement(item, "upnp:album").text = str(song.album.name)
                         SubElement(item, "upnp:genre").text = str(song.album.genre.name)
                         SubElement(item, "upnp:originalTrackNumber").text = str(song.track_number)
                         resource = SubElement(item, "res")
                         resource.attrib["protocolInfo"] = "http-get:*:%s:*" % str(song.file.mimetype)
                         resource.attrib["size"] = str(song.file.size)
                         resource.text = "http://%s:%i/content/%i" % (host, port, song.id)
             if segments[1] == 'playlists':
                 if len(segments) == 2:
                     qset = Playlist.objects.all()
                     matches,total_matches,number_returned = getMatches(startingIndex, requestedCount, qset)
                     for playlist in matches:
                         container = SubElement(didl, "container")
                         container.attrib["id"] = objectID + '/' + str(playlist.id)
                         container.attrib["parentID"] = '/'.join(segments[:-1])
                         container.attrib["restricted"] = "1"
                         container.attrib['childCount'] = str(len(playlist))
                         SubElement(container, "upnp:class").text = "object.container.playlistContainer"
                         SubElement(container, "dc:title").text = playlist.name
                 elif len(segments) == 3:
                     playlist = Playlist.objects.get(id=segments[2])
                     qset = playlist.list_songs()
                     matches,total_matches,number_returned = getMatches(startingIndex, requestedCount, qset)
                     for song in matches:
                         item = SubElement(didl, "item")
                         item.attrib["id"] = objectID + '/' + str(song.id)
                         item.attrib["parentID"] = '/'.join(segments[:-1])
                         item.attrib["restricted"] = "1"
                         SubElement(item, "upnp:class").text = "object.item.audioItem.musicTrack"
                         SubElement(item, "dc:title").text = song.name
                         SubElement(item, "upnp:artist").text = str(song.artist.name)
                         SubElement(item, "upnp:album").text = str(song.album.name)
                         SubElement(item, "upnp:genre").text = str(song.album.genre.name)
                         startingIndex += 1
                         SubElement(item, "upnp:originalTrackNumber").text = str(startingIndex)
                         resource = SubElement(item, "res")
                         resource.attrib["protocolInfo"] = "http-get:*:%s:*" % str(song.file.mimetype)
                         resource.attrib["size"] = str(song.file.size)
                         resource.text = "http://%s:%i/content/%i" % (host, port, song.id)
     else:
         raise UPNPError(402, "unknown browse flag %s" % browseFlag)
     result = xmlprint(didl, pretty=False, withXMLDecl=False)
     update_id = 0
     return {
         'NumberReturned': number_returned,
         'TotalMatches': total_matches,
         'Result': result,
         'UpdateID': update_id
         }