diff --git a/src/calibre/devices/mtp/driver.py b/src/calibre/devices/mtp/driver.py index 9ac0c3d31a..8f8f4d119b 100644 --- a/src/calibre/devices/mtp/driver.py +++ b/src/calibre/devices/mtp/driver.py @@ -7,13 +7,13 @@ __license__ = 'GPL v3' __copyright__ = '2012, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import json, traceback, posixpath, importlib +import json, traceback, posixpath, importlib, os from io import BytesIO from calibre import prints from calibre.constants import iswindows, numeric_version from calibre.devices.mtp.base import debug -from calibre.ptempfile import SpooledTemporaryFile +from calibre.ptempfile import SpooledTemporaryFile, PersistentTemporaryDirectory from calibre.utils.config import from_json, to_json from calibre.utils.date import now, isoformat @@ -199,10 +199,32 @@ class MTP_DEVICE(BASE): # }}} + # Get files from the device {{{ def get_file(self, path, outfile, end_session=True): f = self.filesystem_cache.resolve_mtp_id_path(path) self.get_mtp_file(f, outfile) + def prepare_addable_books(self, paths): + tdir = PersistentTemporaryDirectory('_prepare_mtp') + ans = [] + for path in paths: + try: + f = self.filesystem_cache.resolve_mtp_id_path(path) + except Exception as e: + ans.append((path, e, traceback.format_exc())) + continue + base = os.path.join(tdir, '%s'%f.object_id) + os.mkdir(base) + with open(os.path.join(base, f.name), 'wb') as out: + try: + self.get_mtp_file(f, out) + except Exception as e: + ans.append((path, e, traceback.format_exc())) + else: + ans.append(out.name) + return ans + # }}} + def create_upload_path(self, path, mdata, fname): from calibre.devices import create_upload_path from calibre.utils.filenames import ascii_filename as sanitize diff --git a/src/calibre/gui2/actions/add.py b/src/calibre/gui2/actions/add.py index 9d15fa4ac8..ef7ed7a594 100644 --- a/src/calibre/gui2/actions/add.py +++ b/src/calibre/gui2/actions/add.py @@ -10,9 +10,9 @@ from functools import partial from PyQt4.Qt import QPixmap, QTimer - -from calibre.gui2 import error_dialog, choose_files, \ - choose_dir, warning_dialog, info_dialog +from calibre import as_unicode +from calibre.gui2 import (error_dialog, choose_files, choose_dir, + warning_dialog, info_dialog) from calibre.gui2.dialogs.add_empty_book import AddEmptyBookDialog from calibre.gui2.dialogs.progress import ProgressDialog from calibre.gui2.widgets import IMAGE_EXTENSIONS @@ -400,12 +400,45 @@ class AddAction(InterfaceAction): d = error_dialog(self.gui, _('Add to library'), _('No book files found')) d.exec_() return - paths = self.gui.device_manager.device.prepare_addable_books(paths) - from calibre.gui2.add import Adder - self.__adder_func = partial(self._add_from_device_adder, on_card=None, - model=view.model()) - self._adder = Adder(self.gui, self.gui.library_view.model().db, - self.Dispatcher(self.__adder_func), spare_server=self.gui.spare_server) - self._adder.add(paths) + + self.gui.device_manager.prepare_addable_books(self.Dispatcher(partial( + self.books_prepared, view)), paths) + self.bpd = ProgressDialog(_('Downloading books'), + msg=_('Downloading books from device'), parent=self.gui, + cancelable=False) + QTimer.singleShot(1000, self.show_bpd) + + def show_bpd(self): + if self.bpd is not None: + self.bpd.show() + + def books_prepared(self, view, job): + self.bpd.hide() + self.bpd = None + if job.exception is not None: + self.gui.device_job_exception(job) + return + paths = job.result + ok_paths = [x for x in paths if isinstance(x, basestring)] + failed_paths = [x for x in paths if isinstance(x, tuple)] + if failed_paths: + if not ok_paths: + msg = _('Could not download files from the device') + typ = error_dialog + else: + msg = _('Could not download some files from the device') + typ = warning_dialog + det_msg = [x[0]+ '\n ' + as_unicode(x[1]) for x in failed_paths] + det_msg = '\n\n'.join(det_msg) + typ(self.gui, _('Could not download files'), msg, det_msg=det_msg, + show=True) + + if ok_paths: + from calibre.gui2.add import Adder + self.__adder_func = partial(self._add_from_device_adder, on_card=None, + model=view.model()) + self._adder = Adder(self.gui, self.gui.library_view.model().db, + self.Dispatcher(self.__adder_func), spare_server=self.gui.spare_server) + self._adder.add(ok_paths) diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index d5879042b4..5f9cb3e75c 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -443,6 +443,14 @@ class DeviceManager(Thread): # {{{ return self.create_job_step(self._books, done, description=_('Get list of books on device'), to_job=add_as_step_to_job) + def _prepare_addable_books(self, paths): + return self.device.prepare_addable_books(paths) + + def prepare_addable_books(self, done, paths, add_as_step_to_job=None): + return self.create_job_step(self._prepare_addable_books, done, args=[paths], + description=_('Prepare files for transfer from device'), + to_job=add_as_step_to_job) + def _annotations(self, path_map): return self.device.get_annotations(path_map)