Skip to content

Commit

Permalink
An option to multiple add books from inside a ZIP or RAR file. Right …
Browse files Browse the repository at this point in the history
…click the Add Books button and choose 'Add multiple books from archive'.
  • Loading branch information
kovidgoyal committed Mar 6, 2014
1 parent bdb2d0a commit 8b7956f
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 4 deletions.
2 changes: 2 additions & 0 deletions manual/gui.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ Add books

3. **Add books from directories, including sub-directories (Multiple books per directory, assumes every ebook file is a different book)**: Allows you to choose a directory. The directory and all its sub-directories are scanned recursively and any ebooks found are added to the library. |app| assumes that each directory contains many books. All ebook files with the same name in a directory are assumed to be the same book in different formats. Ebooks with different names are added as different books.

4. **Add multiple books from archive (ZIP/RAR)**: Allows you to add multiple ebooks that are stored inside a single ZIP or RAR file. It is a convenient shortcut that avoids having to first unzip the archive and then add the books via one of the above two options.

4. **Add empty book. (Book Entry with no formats)**: Allows you to create a blank book record. This can be used to then manually fill out the information about a book that you may not have yet in your collection.

5. **Add from ISBN**: Allows you to add one or more books by entering their ISBNs.
Expand Down
18 changes: 17 additions & 1 deletion src/calibre/gui2/actions/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ def genesis(self):
'sub directories (Multiple books per directory, assumes every '
'ebook file is a different book)')).triggered.connect(
self.add_recursive_multiple)
arm = self.add_archive_menu = self.add_menu.addMenu(_('Add multiple books from archive (ZIP/RAR)'))
self.create_menu_action(arm, 'recursive-single-archive', _(
'One book per directory in the archive')).triggered.connect(partial(self.add_archive, True))
self.create_menu_action(arm, 'recursive-multiple-archive', _(
'Multiple books per directory in the archive')).triggered.connect(partial(self.add_archive, False))
self.add_menu.addSeparator()
self.add_menu.addSeparator()
ma('add-empty', _('Add Empty book. (Book entry with no formats)'),
shortcut='Shift+Ctrl+E').triggered.connect(self.add_empty)
Expand Down Expand Up @@ -135,11 +141,21 @@ def add_formats(self, *args):
if current_idx.isValid():
view.model().current_changed(current_idx, current_idx)

def add_archive(self, single):
paths = choose_files(
self.gui, 'recursive-archive-add', _('Choose archive file'),
filters=[(_('Archives'), ('zip', 'rar'))], all_files=False, select_only_single_file=True)
if paths:
self.do_add_recursive(paths[0], single)

def add_recursive(self, single):
root = choose_dir(self.gui, 'recursive book import root dir dialog',
'Select root folder')
_('Select root folder'))
if not root:
return
self.do_add_recursive(root, single)

def do_add_recursive(self, root, single):
from calibre.gui2.add import Adder
self._adder = Adder(self.gui,
self.gui.library_view.model().db,
Expand Down
39 changes: 36 additions & 3 deletions src/calibre/gui2/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from PyQt4.Qt import QThread, QObject, Qt, QProgressDialog, pyqtSignal, QTimer

from calibre.ptempfile import PersistentTemporaryDirectory
from calibre.gui2.dialogs.progress import ProgressDialog
from calibre.gui2 import (error_dialog, info_dialog, gprefs,
warning_dialog, available_width)
Expand Down Expand Up @@ -54,10 +55,11 @@ class RecursiveFind(QThread): # {{{
update = pyqtSignal(object)
found = pyqtSignal(object)

def __init__(self, parent, db, root, single):
def __init__(self, parent, db, root, single, tdir=None):
QThread.__init__(self, parent)
self.db = db
self.path = root
self.tdir = tdir
self.single_book_per_directory = single
self.canceled = False

Expand All @@ -72,7 +74,34 @@ def walk(self, root):
self.books += list(self.db.find_books_in_directory(dirpath[0],
self.single_book_per_directory))

def extract(self):
if self.path.lower().endswith('.zip'):
from calibre.utils.zipfile import ZipFile
try:
with ZipFile(self.path) as zf:
zf.extractall(self.tdir)
except Exception:
prints('Corrupt ZIP file, trying to use local headers')
from calibre.utils.localunzip import extractall
extractall(self.path, self.tdir)
elif self.path.lower().endswith('.rar'):
from calibre.utils.unrar import extract
extract(self.path, self.tdir)
else:
raise ValueError('Can only process ZIP or RAR archives')

def run(self):
if self.tdir is not None:
try:
self.extract()
except Exception as err:
import traceback
traceback.print_exc()
msg = as_unicode(err)
self.found.emit(msg)
return
self.path = self.tdir

root = os.path.abspath(self.path)
try:
self.walk(root)
Expand Down Expand Up @@ -263,12 +292,16 @@ def __init__(self, parent, db, callback, spare_server=None):
self.pd.canceled_signal.connect(self.canceled)

def add_recursive(self, root, single=True):
self.path = root
if os.path.exists(root) and os.path.isfile(root) and root.lower().rpartition('.')[-1] in {'zip', 'rar'}:
self.path = tdir = PersistentTemporaryDirectory('_arcv_')
else:
self.path = root
tdir = None
self.pd.set_msg(_('Searching in all sub-directories...'))
self.pd.set_min(0)
self.pd.set_max(0)
self.pd.value = 0
self.rfind = RecursiveFind(self, self.db, root, single)
self.rfind = RecursiveFind(self, self.db, root, single, tdir=tdir)
self.rfind.update.connect(self.pd.set_msg, type=Qt.QueuedConnection)
self.rfind.found.connect(self.add, type=Qt.QueuedConnection)
self.rfind.start()
Expand Down

0 comments on commit 8b7956f

Please sign in to comment.