MTP: Implement prepare_addable_books and refactor the GUI to run prepare_addable_books in the device thread

This commit is contained in:
Kovid Goyal 2012-09-01 23:00:40 +05:30
parent b9737b9659
commit 2e66bd1aa5
3 changed files with 75 additions and 12 deletions

View File

@ -7,13 +7,13 @@ __license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import json, traceback, posixpath, importlib import json, traceback, posixpath, importlib, os
from io import BytesIO from io import BytesIO
from calibre import prints from calibre import prints
from calibre.constants import iswindows, numeric_version from calibre.constants import iswindows, numeric_version
from calibre.devices.mtp.base import debug 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.config import from_json, to_json
from calibre.utils.date import now, isoformat 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): def get_file(self, path, outfile, end_session=True):
f = self.filesystem_cache.resolve_mtp_id_path(path) f = self.filesystem_cache.resolve_mtp_id_path(path)
self.get_mtp_file(f, outfile) 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): def create_upload_path(self, path, mdata, fname):
from calibre.devices import create_upload_path from calibre.devices import create_upload_path
from calibre.utils.filenames import ascii_filename as sanitize from calibre.utils.filenames import ascii_filename as sanitize

View File

@ -10,9 +10,9 @@ from functools import partial
from PyQt4.Qt import QPixmap, QTimer from PyQt4.Qt import QPixmap, QTimer
from calibre import as_unicode
from calibre.gui2 import error_dialog, choose_files, \ from calibre.gui2 import (error_dialog, choose_files, choose_dir,
choose_dir, warning_dialog, info_dialog warning_dialog, info_dialog)
from calibre.gui2.dialogs.add_empty_book import AddEmptyBookDialog from calibre.gui2.dialogs.add_empty_book import AddEmptyBookDialog
from calibre.gui2.dialogs.progress import ProgressDialog from calibre.gui2.dialogs.progress import ProgressDialog
from calibre.gui2.widgets import IMAGE_EXTENSIONS 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 = error_dialog(self.gui, _('Add to library'), _('No book files found'))
d.exec_() d.exec_()
return return
paths = self.gui.device_manager.device.prepare_addable_books(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 from calibre.gui2.add import Adder
self.__adder_func = partial(self._add_from_device_adder, on_card=None, self.__adder_func = partial(self._add_from_device_adder, on_card=None,
model=view.model()) model=view.model())
self._adder = Adder(self.gui, self.gui.library_view.model().db, self._adder = Adder(self.gui, self.gui.library_view.model().db,
self.Dispatcher(self.__adder_func), spare_server=self.gui.spare_server) self.Dispatcher(self.__adder_func), spare_server=self.gui.spare_server)
self._adder.add(paths) self._adder.add(ok_paths)

View File

@ -443,6 +443,14 @@ class DeviceManager(Thread): # {{{
return self.create_job_step(self._books, done, return self.create_job_step(self._books, done,
description=_('Get list of books on device'), to_job=add_as_step_to_job) 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): def _annotations(self, path_map):
return self.device.get_annotations(path_map) return self.device.get_annotations(path_map)