mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Implement recursive import assuming multiple ebooks per directory
This commit is contained in:
parent
8b97bb79f7
commit
c7cd76bdc7
@ -49,6 +49,12 @@ def get_metadata(stream, stream_type='lrf', use_libprs_metadata=False):
|
|||||||
if not base.authors:
|
if not base.authors:
|
||||||
base.authors = ['Unknown']
|
base.authors = ['Unknown']
|
||||||
base.smart_update(mi)
|
base.smart_update(mi)
|
||||||
|
if hasattr(stream, 'name'):
|
||||||
|
opfpath = os.path.abspath(os.path.splitext(stream.name)[0]+'.opf')
|
||||||
|
if os.access(opfpath, os.R_OK):
|
||||||
|
mi = opf_metadata(opfpath)
|
||||||
|
if mi is not None:
|
||||||
|
base.smart_update(mi)
|
||||||
return base
|
return base
|
||||||
|
|
||||||
def set_metadata(stream, mi, stream_type='lrf'):
|
def set_metadata(stream, mi, stream_type='lrf'):
|
||||||
@ -104,18 +110,14 @@ def metadata_from_filename(name, pat=None):
|
|||||||
mi.title = name
|
mi.title = name
|
||||||
return mi
|
return mi
|
||||||
|
|
||||||
def libprs_metadata(name):
|
def opf_metadata(opfpath):
|
||||||
if os.path.basename(name) != 'metadata.opf':
|
f = open(opfpath, 'rb')
|
||||||
name = os.path.join(os.path.dirname(name), 'metadata.opf')
|
opf = OPFReader(f, os.path.dirname(opfpath))
|
||||||
name = os.path.abspath(name)
|
|
||||||
if os.access(name, os.R_OK):
|
|
||||||
f = open(name, 'rb')
|
|
||||||
opf = OPFReader(f, os.path.dirname(name))
|
|
||||||
try:
|
try:
|
||||||
if opf.libprs_id is not None:
|
if opf.libprs_id is not None:
|
||||||
mi = MetaInformation(opf, None)
|
mi = MetaInformation(opf, None)
|
||||||
if hasattr(opf, 'cover') and opf.cover:
|
if hasattr(opf, 'cover') and opf.cover:
|
||||||
cpath = os.path.join(os.path.dirname(name), opf.cover)
|
cpath = os.path.join(os.path.dirname(opfpath), opf.cover)
|
||||||
if os.access(cpath, os.R_OK):
|
if os.access(cpath, os.R_OK):
|
||||||
fmt = cpath.rpartition('.')[-1]
|
fmt = cpath.rpartition('.')[-1]
|
||||||
data = open(cpath, 'rb').read()
|
data = open(cpath, 'rb').read()
|
||||||
@ -123,3 +125,12 @@ def libprs_metadata(name):
|
|||||||
return mi
|
return mi
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def libprs_metadata(name):
|
||||||
|
if os.path.basename(name) != 'metadata.opf':
|
||||||
|
name = os.path.join(os.path.dirname(name), 'metadata.opf')
|
||||||
|
name = os.path.abspath(name)
|
||||||
|
if os.access(name, os.R_OK):
|
||||||
|
return opf_metadata(name)
|
||||||
|
|
@ -120,11 +120,13 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
self.metadata_menu = md
|
self.metadata_menu = md
|
||||||
self.add_menu = QMenu()
|
self.add_menu = QMenu()
|
||||||
self.add_menu.addAction(_('Add books from a single directory'))
|
self.add_menu.addAction(_('Add books from a single directory'))
|
||||||
self.add_menu.addAction(_('Add books recursively (One book per directory)'))
|
self.add_menu.addAction(_('Add books recursively (One book per directory, assumes every ebook file is the same book in a different format)'))
|
||||||
|
self.add_menu.addAction(_('Add books recursively (Multiple books per directory, assumes every ebook file is a different book)'))
|
||||||
self.action_add.setMenu(self.add_menu)
|
self.action_add.setMenu(self.add_menu)
|
||||||
QObject.connect(self.action_add, SIGNAL("triggered(bool)"), self.add_books)
|
QObject.connect(self.action_add, SIGNAL("triggered(bool)"), self.add_books)
|
||||||
QObject.connect(self.add_menu.actions()[0], SIGNAL("triggered(bool)"), self.add_books)
|
QObject.connect(self.add_menu.actions()[0], SIGNAL("triggered(bool)"), self.add_books)
|
||||||
QObject.connect(self.add_menu.actions()[1], SIGNAL("triggered(bool)"), self.add_recursive_single)
|
QObject.connect(self.add_menu.actions()[1], SIGNAL("triggered(bool)"), self.add_recursive_single)
|
||||||
|
QObject.connect(self.add_menu.actions()[2], SIGNAL("triggered(bool)"), self.add_recursive_multiple)
|
||||||
QObject.connect(self.action_del, SIGNAL("triggered(bool)"), self.delete_books)
|
QObject.connect(self.action_del, SIGNAL("triggered(bool)"), self.delete_books)
|
||||||
QObject.connect(self.action_edit, SIGNAL("triggered(bool)"), self.edit_metadata)
|
QObject.connect(self.action_edit, SIGNAL("triggered(bool)"), self.edit_metadata)
|
||||||
QObject.connect(md.actions()[0], SIGNAL('triggered(bool)'), self.edit_metadata)
|
QObject.connect(md.actions()[0], SIGNAL('triggered(bool)'), self.edit_metadata)
|
||||||
@ -294,15 +296,11 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
################################# Add books ################################
|
################################# Add books ################################
|
||||||
|
|
||||||
def add_recursive_single(self, checked):
|
def add_recursive(self, single):
|
||||||
'''
|
|
||||||
Add books from the local filesystem to either the library or the device
|
|
||||||
recursively assuming one book per folder.
|
|
||||||
'''
|
|
||||||
root = choose_dir(self, 'recursive book import root dir dialog', 'Select root folder')
|
root = choose_dir(self, 'recursive book import root dir dialog', 'Select root folder')
|
||||||
if not root:
|
if not root:
|
||||||
return
|
return
|
||||||
duplicates = self.library_view.model().db.recursive_import(root)
|
duplicates = self.library_view.model().db.recursive_import(root, single)
|
||||||
|
|
||||||
if duplicates:
|
if duplicates:
|
||||||
files = _('<p>Books with the same title as the following already exist in the database. Add them anyway?<ul>')
|
files = _('<p>Books with the same title as the following already exist in the database. Add them anyway?<ul>')
|
||||||
@ -316,6 +314,22 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
self.library_view.model().resort()
|
self.library_view.model().resort()
|
||||||
self.library_view.model().research()
|
self.library_view.model().research()
|
||||||
|
|
||||||
|
def add_recursive_single(self, checked):
|
||||||
|
'''
|
||||||
|
Add books from the local filesystem to either the library or the device
|
||||||
|
recursively assuming one book per folder.
|
||||||
|
'''
|
||||||
|
self.add_recursive(True)
|
||||||
|
|
||||||
|
def add_recursive_multiple(self, checked):
|
||||||
|
'''
|
||||||
|
Add books from the local filesystem to either the library or the device
|
||||||
|
recursively assuming multiple books per folder.
|
||||||
|
'''
|
||||||
|
self.add_recursive(False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_books(self, checked):
|
def add_books(self, checked):
|
||||||
'''
|
'''
|
||||||
|
@ -1355,6 +1355,42 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
|
|||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
def import_book_directory_multiple(self, dirpath, add_duplicates=False):
|
||||||
|
mi = MetaInformation(None, None)
|
||||||
|
dirpath = os.path.abspath(dirpath)
|
||||||
|
duplicates = []
|
||||||
|
for path in os.listdir(dirpath):
|
||||||
|
path = os.path.join(dirpath, path)
|
||||||
|
if os.path.isdir(path) or not os.access(path, os.R_OK):
|
||||||
|
continue
|
||||||
|
ext = os.path.splitext(path)[1]
|
||||||
|
if not ext:
|
||||||
|
continue
|
||||||
|
ext = ext[1:].lower()
|
||||||
|
if ext not in BOOK_EXTENSIONS:
|
||||||
|
continue
|
||||||
|
stream = open(path, 'rb')
|
||||||
|
mi.smart_update(get_metadata(stream, stream_type=ext, use_libprs_metadata=False))
|
||||||
|
if mi.title is None:
|
||||||
|
continue
|
||||||
|
if not add_duplicates and self.conn.execute('SELECT id FROM books where title=?', (mi.title,)).fetchone():
|
||||||
|
duplicates.append((mi, path))
|
||||||
|
continue
|
||||||
|
series_index = 1 if mi.series_index is None else mi.series_index
|
||||||
|
obj = self.conn.execute('INSERT INTO books(title, uri, series_index) VALUES (?, ?, ?)',
|
||||||
|
(mi.title, None, series_index))
|
||||||
|
id = obj.lastrowid
|
||||||
|
self.conn.commit()
|
||||||
|
self.set_metadata(id, mi)
|
||||||
|
stream.seek(0, 2)
|
||||||
|
usize = stream.tell()
|
||||||
|
stream.seek(0)
|
||||||
|
self.conn.execute('INSERT INTO data(book, format, uncompressed_size, data) VALUES (?,?,?,?)',
|
||||||
|
(id, ext, usize, sqlite.Binary(compress(stream.read()))))
|
||||||
|
self.conn.commit()
|
||||||
|
return duplicates
|
||||||
|
|
||||||
|
|
||||||
def import_book_directory(self, dirpath, add_duplicates=False):
|
def import_book_directory(self, dirpath, add_duplicates=False):
|
||||||
mi = MetaInformation(None, None)
|
mi = MetaInformation(None, None)
|
||||||
dirpath = os.path.abspath(dirpath)
|
dirpath = os.path.abspath(dirpath)
|
||||||
@ -1371,6 +1407,7 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
|
|||||||
continue
|
continue
|
||||||
f = open(path, 'rb')
|
f = open(path, 'rb')
|
||||||
mi.smart_update(get_metadata(f, stream_type=ext, use_libprs_metadata=True))
|
mi.smart_update(get_metadata(f, stream_type=ext, use_libprs_metadata=True))
|
||||||
|
f.close()
|
||||||
formats.append((ext, path))
|
formats.append((ext, path))
|
||||||
if mi.title is None or not formats:
|
if mi.title is None or not formats:
|
||||||
return
|
return
|
||||||
@ -1392,13 +1429,16 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
|
|||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
|
|
||||||
|
|
||||||
def recursive_import(self, root):
|
def recursive_import(self, root, single_book_per_directory=True):
|
||||||
root = os.path.abspath(root)
|
root = os.path.abspath(root)
|
||||||
duplicates = []
|
duplicates = []
|
||||||
for dirpath in os.walk(root):
|
for dirpath in os.walk(root):
|
||||||
res = self.import_book_directory(dirpath[0])
|
res = self.import_book_directory(dirpath[0]) if single_book_per_directory else self.import_book_directory_multiple(dirpath[0])
|
||||||
if res is not None:
|
if res is not None:
|
||||||
|
if single_book_per_directory:
|
||||||
duplicates.append(res)
|
duplicates.append(res)
|
||||||
|
else:
|
||||||
|
duplicates.extend(res)
|
||||||
return duplicates
|
return duplicates
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user