'Add a book to the database. self.data and self.cache are not updated.
@param paths: List of paths to book files of file-like objects'

def add_books(self, paths, formats, metadata, uris=[], add_duplicates=True):

    (formats, metadata, uris) = (iter(formats), iter(metadata), iter(uris))
    duplicates = []
    for path in paths:
        mi = metadata.next()
        format = formats.next()
        try:
            uri = uris.next()
        except StopIteration:
            uri = None
        if ((not add_duplicates) and self.has_book(mi)):
            duplicates.append((path, format, mi, uri))
            continue
        series_index = (1 if (mi.series_index is None) else mi.series_index)
        aus = (mi.author_sort if mi.author_sort else ',    '.join(mi.authors))
        obj = self.conn.execute('INSERT    INTO    books(title,    uri,    series_index,    author_sort)    VALUES    (?,    ?,    ?,    ?)', (mi.title, uri, series_index, aus))
        id = obj.lastrowid
        self.conn.commit()
        self.set_metadata(id, mi)
        stream = (path if hasattr(path, 'read') else lopen(path, 'rb'))
        stream.seek(0, 2)
        usize = stream.tell()
        stream.seek(0)
        self.conn.execute('INSERT    INTO    data(book,    format,    uncompressed_size,    data)    VALUES    (?,?,?,?)', (id, format, usize, sqlite.Binary(compress(stream.read()))))
        if (not hasattr(path, 'read')):
            stream.close()
    self.conn.commit()
    if duplicates:
        paths = tuple((duplicate[0] for duplicate in duplicates))
        formats = tuple((duplicate[1] for duplicate in duplicates))
        metadata = tuple((duplicate[2] for duplicate in duplicates))
        uris = tuple((duplicate[3] for duplicate in duplicates))
        return (paths, formats, metadata, uris)
    return None
