Ejemplo n.º 1
0
    def __init__(self, server, **kwargs):
        BackendStore.__init__(self,server)
        self.next_id = 1000
        self.name = kwargs.get('name','my media')
        self.content = kwargs.get('content',None)
        if self.content != None:
                if isinstance(self.content,basestring):
                    self.content = [self.content]
                l = []
                for a in self.content:
                    l += a.split(',')
                self.content = l
        else:
            self.content = xdg_content()
        if self.content == None:
            self.content = 'tests/content'
        if not isinstance( self.content, list):
            self.content = [self.content]
        self.urlbase = kwargs.get('urlbase','')
        ignore_patterns = kwargs.get('ignore_patterns',[])

        if self.urlbase[len(self.urlbase)-1] != '/':
            self.urlbase += '/'
        self.server = server
        self.store = {}

        try:
            self.inotify = INotify()
        except:
            self.inotify = None

        if kwargs.get('enable_destroy','no') == 'yes':
            self.upnp_DestroyObject = self.hidden_upnp_DestroyObject

        self.ignore_file_pattern = re.compile('|'.join(['^\..*'] + list(ignore_patterns)))
        parent = None
        self.update_id = 0
        if len(self.content)>1:
            UPnPClass = classChooser('root')
            id = self.getnextID()
            parent = self.store[id] = FSItem( id, parent, 'media', 'root', self.urlbase, UPnPClass, update=True)

        for path in self.content:
            if isinstance(path,(list,tuple)):
                path = path[0]
            if self.ignore_file_pattern.match(path):
                continue
            self.walk(path, parent, self.ignore_file_pattern)

        self.wmc_mapping.update({'14': 0,
                                 '15': 0,
                                 '16': 0,
                                 '17': 0
                                })

        louie.send('Coherence.UPnP.Backend.init_completed', None, backend=self)
Ejemplo n.º 2
0
    def __init__(self, server, **kwargs):
        BackendStore.__init__(self, server, **kwargs)
        self.next_id = 1000
        self.name = kwargs.get('name', 'my media')
        self.content = kwargs.get('content', None)
        if self.content != None:
            if isinstance(self.content, str):
                self.content = [self.content]
            l = []
            for a in self.content:
                l += a.split(',')
            self.content = l
        else:
            self.content = xdg_content()
            self.content = [x[0] for x in self.content]
        if self.content == None:
            self.content = 'tests/content'
        if not isinstance(self.content, list):
            self.content = [self.content]
        self.content = Set([os.path.abspath(x) for x in self.content])
        ignore_patterns = kwargs.get('ignore_patterns', [])
        self.store = {}

        self.inotify = None

        if kwargs.get('enable_inotify', 'yes') == 'yes':
            if INotify:
                try:
                    self.inotify = INotify()
                except Exception as msg:
                    self.info("%s", msg)
            else:
                self.info("%s", no_inotify_reason)
        else:
            self.info("FSStore content auto-update disabled upon user request")

        if kwargs.get('enable_destroy', 'no') == 'yes':
            self.upnp_DestroyObject = self.hidden_upnp_DestroyObject

        self.import_folder = kwargs.get('import_folder', None)
        if self.import_folder != None:
            self.import_folder = os.path.abspath(self.import_folder)
            if not os.path.isdir(self.import_folder):
                self.import_folder = None

        self.ignore_file_pattern = re.compile('|'.join(['^\..*'] +
                                                       list(ignore_patterns)))
        parent = None
        self.update_id = 0
        if (len(self.content) > 1
                or utils.means_true(kwargs.get('create_root', False))
                or self.import_folder != None):
            UPnPClass = classChooser('root')
            id = str(self.getnextID())
            parent = self.store[id] = FSItem(id,
                                             parent,
                                             'media',
                                             'root',
                                             self.urlbase,
                                             UPnPClass,
                                             update=True,
                                             store=self)

        if self.import_folder != None:
            id = str(self.getnextID())
            self.store[id] = FSItem(id,
                                    parent,
                                    self.import_folder,
                                    'directory',
                                    self.urlbase,
                                    UPnPClass,
                                    update=True,
                                    store=self)
            self.import_folder_id = id

        for path in self.content:
            if isinstance(path, (list, tuple)):
                path = path[0]
            if self.ignore_file_pattern.match(path):
                continue
            try:
                path = path.encode('utf-8')  # patch for #267
                self.walk(path, parent, self.ignore_file_pattern)
            except Exception as msg:
                self.warning('on walk of %r: %r', path, msg)
                import traceback
                self.debug(traceback.format_exc())

        self.wmc_mapping.update({'14': '0', '15': '0', '16': '0', '17': '0'})

        louie.send('Coherence.UPnP.Backend.init_completed', None, backend=self)
Ejemplo n.º 3
0
class FSStore(BackendStore):
    logCategory = 'fs_store'

    implements = ['MediaServer']

    def __init__(self, server, **kwargs):
        BackendStore.__init__(self,server)
        self.next_id = 1000
        self.name = kwargs.get('name','my media')
        self.content = kwargs.get('content',None)
        if self.content != None:
                if isinstance(self.content,basestring):
                    self.content = [self.content]
                l = []
                for a in self.content:
                    l += a.split(',')
                self.content = l
        else:
            self.content = xdg_content()
        if self.content == None:
            self.content = 'tests/content'
        if not isinstance( self.content, list):
            self.content = [self.content]
        self.urlbase = kwargs.get('urlbase','')
        ignore_patterns = kwargs.get('ignore_patterns',[])

        if self.urlbase[len(self.urlbase)-1] != '/':
            self.urlbase += '/'
        self.server = server
        self.store = {}

        try:
            self.inotify = INotify()
        except:
            self.inotify = None

        if kwargs.get('enable_destroy','no') == 'yes':
            self.upnp_DestroyObject = self.hidden_upnp_DestroyObject

        self.ignore_file_pattern = re.compile('|'.join(['^\..*'] + list(ignore_patterns)))
        parent = None
        self.update_id = 0
        if len(self.content)>1:
            UPnPClass = classChooser('root')
            id = self.getnextID()
            parent = self.store[id] = FSItem( id, parent, 'media', 'root', self.urlbase, UPnPClass, update=True)

        for path in self.content:
            if isinstance(path,(list,tuple)):
                path = path[0]
            if self.ignore_file_pattern.match(path):
                continue
            self.walk(path, parent, self.ignore_file_pattern)

        self.wmc_mapping.update({'14': 0,
                                 '15': 0,
                                 '16': 0,
                                 '17': 0
                                })

        louie.send('Coherence.UPnP.Backend.init_completed', None, backend=self)

    def __repr__(self):
        return str(self.__class__).split('.')[-1]

    def release(self):
        if self.inotify != None:
            self.inotify.release()

    def len(self):
        return len(self.store)

    def get_by_id(self,id):
        # we have referenced ids here when we are in WMC mapping mode
        if isinstance(id, basestring):
            id = id.split('@',1)
            id = id[0]
        try:
            id = int(id)
        except ValueError:
            id = 1000

        if id == 0:
            id = 1000
        try:
            return self.store[id]
        except:
            return None

    def get_id_by_name(self, parent, name):
        try:
            parent = self.store[int(parent)]
            for child in parent.children:
                if not isinstance(name, unicode):
                    name = name.decode("utf8")
                if name == child.get_name():
                    return child.id
        except:
            pass

        return None

    def walk(self, path, parent=None, ignore_file_pattern=''):
        containers = []
        parent = self.append(path,parent)
        if parent != None:
            containers.append(parent)
        while len(containers)>0:
            container = containers.pop()
            try:
                for child in container.location.children():
                    if ignore_file_pattern.match(child.basename()) != None:
                        continue
                    new_container = self.append(child.path,container)
                    if new_container != None:
                        containers.append(new_container)
            except UnicodeDecodeError:
                self.warning("UnicodeDecodeError - there is something wrong with a file located in %r", container.get_path())

    def create(self, mimetype, path, parent):
        #print "create", mimetype, path, type(path), parent
        UPnPClass = classChooser(mimetype)
        if UPnPClass == None:
            return None

        id = self.getnextID()
        update = False
        if hasattr(self, 'update_id'):
            update = True

        self.store[id] = FSItem( id, parent, path, mimetype, self.urlbase, UPnPClass, update=True)
        if hasattr(self, 'update_id'):
            self.update_id += 1
            #print self.update_id
            if self.server:
                if hasattr(self.server,'content_directory_server'):
                    self.server.content_directory_server.set_variable(0, 'SystemUpdateID', self.update_id)
            if parent is not None:
                value = (parent.get_id(),parent.get_update_id())
                if self.server:
                    if hasattr(self.server,'content_directory_server'):
                        self.server.content_directory_server.set_variable(0, 'ContainerUpdateIDs', value)

        return id

    def append(self,path,parent):
        #print "append", path, type(path), parent
        try:
            mimetype,_ = mimetypes.guess_type(path, strict=False)
            if mimetype == None:
                if os.path.isdir(path):
                    mimetype = 'directory'
            if mimetype == None:
                return None

            id = self.create(mimetype,path,parent)

            if mimetype == 'directory':
                if self.inotify is not None:
                    mask = IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO | IN_CHANGED
                    self.inotify.watch(path, mask=mask, auto_add=False, callbacks=(self.notify,id))
                return self.store[id]
        except OSError, msg:
            """ seems we have some permissions issues along the content path """
            self.warning("path %r isn't accessible, error %r", path, msg)

        return None
Ejemplo n.º 4
0
class FSStore(BackendStore):
    logCategory = 'fs_store'

    implements = ['MediaServer']

    description = """MediaServer exporting files from the file-system"""

    options = [{
        'option':
        'name',
        'type':
        'string',
        'default':
        'my media',
        'help':
        'the name under this MediaServer shall show up with on other UPnP clients'
    }, {
        'option': 'version',
        'type': 'int',
        'default': 2,
        'enum': (2, 1),
        'help': 'the highest UPnP version this MediaServer shall support',
        'level': 'advance'
    }, {
        'option': 'uuid',
        'type': 'string',
        'help':
        'the unique (UPnP) identifier for this MediaServer, usually automatically set',
        'level': 'advance'
    }, {
        'option': 'content',
        'type': 'string',
        'default': xdg_content(),
        'help': 'the path(s) this MediaServer shall export'
    }, {
        'option':
        'ignore_patterns',
        'type':
        'string',
        'help':
        'list of regex patterns, matching filenames will be ignored'
    }, {
        'option': 'enable_inotify',
        'type': 'string',
        'default': 'yes',
        'help': 'enable real-time monitoring of the content folders'
    }, {
        'option': 'enable_destroy',
        'type': 'string',
        'default': 'no',
        'help': 'enable deleting a file via an UPnP method'
    }, {
        'option':
        'import_folder',
        'type':
        'string',
        'help':
        'The path to store files imported via an UPnP method, if empty the Import method is disabled'
    }]

    def __init__(self, server, **kwargs):
        BackendStore.__init__(self, server, **kwargs)
        self.next_id = 1000
        self.name = kwargs.get('name', 'my media')
        self.content = kwargs.get('content', None)
        if self.content != None:
            if isinstance(self.content, str):
                self.content = [self.content]
            l = []
            for a in self.content:
                l += a.split(',')
            self.content = l
        else:
            self.content = xdg_content()
            self.content = [x[0] for x in self.content]
        if self.content == None:
            self.content = 'tests/content'
        if not isinstance(self.content, list):
            self.content = [self.content]
        self.content = Set([os.path.abspath(x) for x in self.content])
        ignore_patterns = kwargs.get('ignore_patterns', [])
        self.store = {}

        self.inotify = None

        if kwargs.get('enable_inotify', 'yes') == 'yes':
            if INotify:
                try:
                    self.inotify = INotify()
                except Exception as msg:
                    self.info("%s", msg)
            else:
                self.info("%s", no_inotify_reason)
        else:
            self.info("FSStore content auto-update disabled upon user request")

        if kwargs.get('enable_destroy', 'no') == 'yes':
            self.upnp_DestroyObject = self.hidden_upnp_DestroyObject

        self.import_folder = kwargs.get('import_folder', None)
        if self.import_folder != None:
            self.import_folder = os.path.abspath(self.import_folder)
            if not os.path.isdir(self.import_folder):
                self.import_folder = None

        self.ignore_file_pattern = re.compile('|'.join(['^\..*'] +
                                                       list(ignore_patterns)))
        parent = None
        self.update_id = 0
        if (len(self.content) > 1
                or utils.means_true(kwargs.get('create_root', False))
                or self.import_folder != None):
            UPnPClass = classChooser('root')
            id = str(self.getnextID())
            parent = self.store[id] = FSItem(id,
                                             parent,
                                             'media',
                                             'root',
                                             self.urlbase,
                                             UPnPClass,
                                             update=True,
                                             store=self)

        if self.import_folder != None:
            id = str(self.getnextID())
            self.store[id] = FSItem(id,
                                    parent,
                                    self.import_folder,
                                    'directory',
                                    self.urlbase,
                                    UPnPClass,
                                    update=True,
                                    store=self)
            self.import_folder_id = id

        for path in self.content:
            if isinstance(path, (list, tuple)):
                path = path[0]
            if self.ignore_file_pattern.match(path):
                continue
            try:
                path = path.encode('utf-8')  # patch for #267
                self.walk(path, parent, self.ignore_file_pattern)
            except Exception as msg:
                self.warning('on walk of %r: %r', path, msg)
                import traceback
                self.debug(traceback.format_exc())

        self.wmc_mapping.update({'14': '0', '15': '0', '16': '0', '17': '0'})

        louie.send('Coherence.UPnP.Backend.init_completed', None, backend=self)

    def __repr__(self):
        return str(self.__class__).split('.')[-1]

    def release(self):
        if self.inotify != None:
            self.inotify.release()

    def len(self):
        return len(self.store)

    def get_by_id(self, id):
        #print "get_by_id", id, type(id)
        # we have referenced ids here when we are in WMC mapping mode
        if isinstance(id, str):
            id = id.split('@', 1)
            id = id[0]
        elif isinstance(id, int):
            id = str(id)
        #try:
        #    id = int(id)
        #except ValueError:
        #    id = 1000

        if id == '0':
            id = '1000'
        #print "get_by_id 2", id
        try:
            r = self.store[id]
        except:
            r = None
        #print "get_by_id 3", r
        return r

    def get_id_by_name(self, parent='0', name=''):
        self.info('get_id_by_name %r (%r) %r', parent, type(parent), name)
        try:
            parent = self.store[parent]
            self.debug("%r %d", parent, len(parent.children))
            for child in parent.children:
                #if not isinstance(name, unicode):
                #    name = name.decode("utf8")
                self.debug("%r %r %r", child.get_name(), child.get_realpath(),
                           name == child.get_realpath())
                if name == child.get_realpath():
                    return child.id
        except:
            import traceback
            self.info(traceback.format_exc())
        self.debug('get_id_by_name not found')

        return None

    def get_url_by_name(self, parent='0', name=''):
        self.info('get_url_by_name %r %r', parent, name)
        id = self.get_id_by_name(parent, name)
        #print 'get_url_by_name', id
        if id == None:
            return ''
        return self.store[id].url

    def update_config(self, **kwargs):
        print("update_config", kwargs)
        if 'content' in kwargs:
            new_content = kwargs['content']
            new_content = Set(
                [os.path.abspath(x) for x in new_content.split(',')])
            new_folders = new_content.difference(self.content)
            obsolete_folders = self.content.difference(new_content)
            print(new_folders, obsolete_folders)
            for folder in obsolete_folders:
                self.remove_content_folder(folder)
            for folder in new_folders:
                self.add_content_folder(folder)
            self.content = new_content

    def add_content_folder(self, path):
        path = os.path.abspath(path)
        if path not in self.content:
            self.content.add(path)
            self.walk(path, self.store['1000'], self.ignore_file_pattern)

    def remove_content_folder(self, path):
        path = os.path.abspath(path)
        if path in self.content:
            id = self.get_id_by_name('1000', path)
            self.remove(id)
            self.content.remove(path)

    def walk(self, path, parent=None, ignore_file_pattern=''):
        self.debug("walk %r", path)
        containers = []
        parent = self.append(path, parent)
        if parent != None:
            containers.append(parent)
        while len(containers) > 0:
            container = containers.pop()
            try:
                self.debug('adding %r', container.location)
                for child in container.location.children():
                    if ignore_file_pattern.match(child.basename()) != None:
                        continue
                    new_container = self.append(child.path, container)
                    if new_container != None:
                        containers.append(new_container)
            except UnicodeDecodeError:
                self.warning(
                    "UnicodeDecodeError - there is something wrong with a file located in %r",
                    container.get_path())

    def create(self, mimetype, path, parent):
        self.debug("create  %s %s %s %s", mimetype, path, type(path), parent)
        UPnPClass = classChooser(mimetype)
        if UPnPClass == None:
            return None

        id = self.getnextID()
        if mimetype in ('root', 'directory'):
            id = str(id)
        else:
            _, ext = os.path.splitext(path)
            id = str(id) + ext.lower()
        update = False
        if hasattr(self, 'update_id'):
            update = True

        self.store[id] = FSItem(id,
                                parent,
                                path,
                                mimetype,
                                self.urlbase,
                                UPnPClass,
                                update=True,
                                store=self)
        if hasattr(self, 'update_id'):
            self.update_id += 1
            #print self.update_id
            if self.server:
                if hasattr(self.server, 'content_directory_server'):
                    self.server.content_directory_server.set_variable(
                        0, 'SystemUpdateID', self.update_id)
            if parent is not None:
                value = (parent.get_id(), parent.get_update_id())
                if self.server:
                    if hasattr(self.server, 'content_directory_server'):
                        self.server.content_directory_server.set_variable(
                            0, 'ContainerUpdateIDs', value)

        return id

    def append(self, path, parent):
        self.debug("append  %s %s %s", path, type(path), parent)
        if os.path.exists(path) == False:
            self.warning("path %r not available - ignored", path)
            return None

        if stat.S_ISFIFO(os.stat(path).st_mode):
            self.warning("path %r is a FIFO - ignored", path)
            return None

        try:
            mimetype, _ = mimetypes.guess_type(path, strict=False)
            if mimetype == None:
                if os.path.isdir(path):
                    mimetype = 'directory'
            if mimetype == None:
                return None

            id = self.create(mimetype, path, parent)

            if mimetype == 'directory':
                if self.inotify is not None:
                    mask = IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO | IN_CHANGED
                    self.inotify.watch(
                        path,
                        mask=mask,
                        autoAdd=False,
                        callbacks=[partial(self.notify, parameter=id)])
                return self.store[id]
        except OSError as msg:
            """ seems we have some permissions issues along the content path """
            self.warning("path %r isn't accessible, error %r", path, msg)

        return None

    def remove(self, id):
        print('FSSTore remove id', id)
        try:
            item = self.store[id]
            parent = item.get_parent()
            item.remove()
            del self.store[id]
            if hasattr(self, 'update_id'):
                self.update_id += 1
                if self.server:
                    self.server.content_directory_server.set_variable(
                        0, 'SystemUpdateID', self.update_id)
                #value = '%d,%d' % (parent.get_id(),parent_get_update_id())
                value = (parent.get_id(), parent.get_update_id())
                if self.server:
                    self.server.content_directory_server.set_variable(
                        0, 'ContainerUpdateIDs', value)

        except:
            pass

    def notify(self, ignore, path, mask, parameter=None):
        self.info("Event %s on %s - parameter %r",
                  ', '.join(self.inotify.flag_to_human(mask)), path.path,
                  parameter)

        if mask & IN_CHANGED:
            # FIXME react maybe on access right changes, loss of read rights?
            #print '%s was changed, parent %d (%s)' % (path, parameter, iwp.path)
            pass

        if (mask & IN_DELETE or mask & IN_MOVED_FROM):
            self.info('%s was deleted, parent %r (%s)', path.path, parameter,
                      path.parent.path)
            id = self.get_id_by_name(parameter, path.path)
            if id != None:
                self.remove(id)
        if (mask & IN_CREATE or mask & IN_MOVED_TO):
            if mask & IN_ISDIR:
                self.info('directory %s was created, parent %r (%s)',
                          path.path, parameter, path.parent.path)
            else:
                self.info('file %s was created, parent %r (%s)', path.path,
                          parameter, path.parent.path)
            if self.get_id_by_name(parameter, path.path) is None:
                if path.isdir():
                    self.walk(path.path, self.get_by_id(parameter),
                              self.ignore_file_pattern)
                else:
                    if self.ignore_file_pattern.match(filename) == None:
                        self.append(path.path, self.get_by_id(parameter))

    def getnextID(self):
        ret = self.next_id
        self.next_id += 1
        return ret

    def backend_import(self, item, data):
        try:
            f = open(item.get_path(), 'w+b')
            if hasattr(data, 'read'):
                data = data.read()
            f.write(data)
            f.close()
            item.rebuild(self.urlbase)
            return 200
        except IOError:
            self.warning("import of file %s failed", item.get_path())
        except Exception as msg:
            import traceback
            self.warning(traceback.format_exc())
        return 500

    def upnp_init(self):
        self.current_connection_id = None
        if self.server:
            self.server.connection_manager_server.set_variable(
                0,
                'SourceProtocolInfo',
                [  #'http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01700000000000000000000000000000',
                    #'http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMABASE;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=01700000000000000000000000000000',
                    #'http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=00f00000000000000000000000000000',
                    #'http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=00f00000000000000000000000000000',
                    #'http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=00f00000000000000000000000000000',
                    #'http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=00f00000000000000000000000000000',
                    #'http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01700000000000000000000000000000',
                    #'http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01700000000000000000000000000000',
                    'internal:%s:audio/mpeg:*' %
                    self.server.coherence.hostname,
                    'http-get:*:audio/mpeg:*',
                    'internal:%s:video/mp4:*' % self.server.coherence.hostname,
                    'http-get:*:video/mp4:*',
                    'internal:%s:application/ogg:*' %
                    self.server.coherence.hostname,
                    'http-get:*:application/ogg:*',
                    'internal:%s:video/x-msvideo:*' %
                    self.server.coherence.hostname,
                    'http-get:*:video/x-msvideo:*',
                    'internal:%s:video/mpeg:*' %
                    self.server.coherence.hostname,
                    'http-get:*:video/mpeg:*',
                    'internal:%s:video/avi:*' % self.server.coherence.hostname,
                    'http-get:*:video/avi:*',
                    'internal:%s:video/divx:*' %
                    self.server.coherence.hostname,
                    'http-get:*:video/divx:*',
                    'internal:%s:video/quicktime:*' %
                    self.server.coherence.hostname,
                    'http-get:*:video/quicktime:*',
                    'internal:%s:image/gif:*' % self.server.coherence.hostname,
                    'http-get:*:image/gif:*',
                    'internal:%s:image/jpeg:*' %
                    self.server.coherence.hostname,
                    'http-get:*:image/jpeg:*'
                ],
                default=True)
            self.server.content_directory_server.set_variable(
                0, 'SystemUpdateID', self.update_id)
            #self.server.content_directory_server.set_variable(0, 'SortCapabilities', '*')

    def upnp_ImportResource(self, *args, **kwargs):
        SourceURI = kwargs['SourceURI']
        DestinationURI = kwargs['DestinationURI']

        if DestinationURI.endswith('?import'):
            id = DestinationURI.split('/')[-1]
            id = id[:-7]  # remove the ?import
        else:
            return failure.Failure(errorCode(718))

        item = self.get_by_id(id)
        if item == None:
            return failure.Failure(errorCode(718))

        def gotPage(headers):
            #print "gotPage", headers
            content_type = headers.get('content-type', [])
            if not isinstance(content_type, list):
                content_type = list(content_type)
            if len(content_type) > 0:
                extension = mimetypes.guess_extension(content_type[0],
                                                      strict=False)
                item.set_path(None, extension)
            shutil.move(tmp_path, item.get_path())
            item.rebuild(self.urlbase)
            if hasattr(self, 'update_id'):
                self.update_id += 1
                if self.server:
                    if hasattr(self.server, 'content_directory_server'):
                        self.server.content_directory_server.set_variable(
                            0, 'SystemUpdateID', self.update_id)
                if item.parent is not None:
                    value = (item.parent.get_id(), item.parent.get_update_id())
                    if self.server:
                        if hasattr(self.server, 'content_directory_server'):
                            self.server.content_directory_server.set_variable(
                                0, 'ContainerUpdateIDs', value)

        def gotError(error, url):
            self.warning("error requesting %s", url)
            self.info(error)
            os.unlink(tmp_path)
            return failure.Failure(errorCode(718))

        tmp_fp, tmp_path = tempfile.mkstemp()
        os.close(tmp_fp)

        utils.downloadPage(SourceURI,
                           tmp_path).addCallbacks(gotPage, gotError, None,
                                                  None, [SourceURI], None)

        transfer_id = 0  # FIXME

        return {'TransferID': transfer_id}

    def upnp_CreateObject(self, *args, **kwargs):
        #print "CreateObject", kwargs
        if kwargs['ContainerID'] == 'DLNA.ORG_AnyContainer':
            if self.import_folder != None:
                ContainerID = self.import_folder_id
            else:
                return failure.Failure(errorCode(712))
        else:
            ContainerID = kwargs['ContainerID']
        Elements = kwargs['Elements']

        parent_item = self.get_by_id(ContainerID)
        if parent_item == None:
            return failure.Failure(errorCode(710))
        if parent_item.item.restricted:
            return failure.Failure(errorCode(713))

        if len(Elements) == 0:
            return failure.Failure(errorCode(712))

        elt = DIDLElement.fromString(Elements)
        if elt.numItems() != 1:
            return failure.Failure(errorCode(712))

        item = elt.getItems()[0]
        if item.parentID == 'DLNA.ORG_AnyContainer':
            item.parentID = ContainerID
        if (item.id != '' or item.parentID != ContainerID
                or item.restricted == True or item.title == ''):
            return failure.Failure(errorCode(712))

        if ('..' in item.title or '~' in item.title or os.sep in item.title):
            return failure.Failure(errorCode(712))

        if item.upnp_class == 'object.container.storageFolder':
            if len(item.res) != 0:
                return failure.Failure(errorCode(712))
            path = os.path.join(parent_item.get_path(), item.title)
            id = self.create('directory', path, parent_item)
            try:
                os.mkdir(path)
            except:
                self.remove(id)
                return failure.Failure(errorCode(712))

            if self.inotify is not None:
                mask = IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO | IN_CHANGED
                self.inotify.watch(
                    path,
                    mask=mask,
                    autoAdd=False,
                    callbacks=[partial(self.notify, parameter=id)])

            new_item = self.get_by_id(id)
            didl = DIDLElement()
            didl.addItem(new_item.item)
            return {'ObjectID': id, 'Result': didl.toString()}

        if item.upnp_class.startswith('object.item'):
            _, _, content_format, _ = item.res[0].protocolInfo.split(':')
            extension = mimetypes.guess_extension(content_format, strict=False)
            path = os.path.join(parent_item.get_realpath(),
                                item.title + extension)
            id = self.create('item', path, parent_item)

            new_item = self.get_by_id(id)
            for res in new_item.item.res:
                res.importUri = new_item.url + '?import'
                res.data = None
            didl = DIDLElement()
            didl.addItem(new_item.item)
            return {'ObjectID': id, 'Result': didl.toString()}

        return failure.Failure(errorCode(712))

    def hidden_upnp_DestroyObject(self, *args, **kwargs):
        ObjectID = kwargs['ObjectID']

        item = self.get_by_id(ObjectID)
        if item == None:
            return failure.Failure(errorCode(701))

        print("upnp_DestroyObject", item.location)
        try:
            item.location.remove()
        except Exception as msg:
            print(Exception, msg)
            return failure.Failure(errorCode(715))

        return {}