mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Enable detection of MTP devices in the GUI and with ebook-device, with a tweak. Note that MTP support is not yet completed.
This commit is contained in:
parent
786729fa6f
commit
5601852363
@ -675,7 +675,6 @@ from calibre.devices.bambook.driver import BAMBOOK
|
||||
from calibre.devices.boeye.driver import BOEYE_BEX, BOEYE_BDX
|
||||
from calibre.devices.smart_device_app.driver import SMART_DEVICE_APP
|
||||
|
||||
|
||||
# Order here matters. The first matched device is the one used.
|
||||
plugins += [
|
||||
HANLINV3,
|
||||
@ -749,6 +748,12 @@ plugins += [
|
||||
SMART_DEVICE_APP,
|
||||
USER_DEFINED,
|
||||
]
|
||||
|
||||
from calibre.utils.config_base import tweaks
|
||||
if tweaks.get('test_mtp_driver', False):
|
||||
from calibre.devices.mtp.driver import MTP_DEVICE
|
||||
plugins.append(MTP_DEVICE)
|
||||
|
||||
# }}}
|
||||
|
||||
# New metadata download plugins {{{
|
||||
|
@ -9,7 +9,7 @@ For usage information run the script.
|
||||
import StringIO, sys, time, os
|
||||
from optparse import OptionParser
|
||||
|
||||
from calibre import __version__, __appname__
|
||||
from calibre import __version__, __appname__, human_readable
|
||||
from calibre.devices.errors import PathError
|
||||
from calibre.utils.terminfo import TerminalController
|
||||
from calibre.devices.errors import ArgumentError, DeviceError, DeviceLocked
|
||||
@ -18,16 +18,6 @@ from calibre.devices.scanner import DeviceScanner
|
||||
|
||||
MINIMUM_COL_WIDTH = 12 #: Minimum width of columns in ls output
|
||||
|
||||
def human_readable(size):
|
||||
""" Convert a size in bytes into a human readle form """
|
||||
if size < 1024: divisor, suffix = 1, ""
|
||||
elif size < 1024*1024: divisor, suffix = 1024., "K"
|
||||
elif size < 1024*1024*1024: divisor, suffix = 1024*1024, "M"
|
||||
elif size < 1024*1024*1024*1024: divisor, suffix = 1024*1024, "G"
|
||||
size = str(size/divisor)
|
||||
if size.find(".") > -1: size = size[:size.find(".")+2]
|
||||
return size + suffix
|
||||
|
||||
class FileFormatter(object):
|
||||
def __init__(self, file, term):
|
||||
self.term = term
|
||||
@ -207,11 +197,19 @@ def main():
|
||||
scanner = DeviceScanner()
|
||||
scanner.scan()
|
||||
connected_devices = []
|
||||
|
||||
for d in device_plugins():
|
||||
try:
|
||||
d.startup()
|
||||
except:
|
||||
print ('Startup failed for device plugin: %s'%d)
|
||||
if d.MANAGES_DEVICE_PRESENCE:
|
||||
cd = d.detect_managed_devices(scanner.devices)
|
||||
if cd is not None:
|
||||
connected_devices.append((cd, d))
|
||||
dev = d
|
||||
break
|
||||
continue
|
||||
ok, det = scanner.is_device_connected(d)
|
||||
if ok:
|
||||
dev = d
|
||||
|
@ -81,6 +81,19 @@ class DevicePlugin(Plugin):
|
||||
#: by.
|
||||
NUKE_COMMENTS = None
|
||||
|
||||
#: If True indicates that this driver completely manages device detection,
|
||||
#: ejecting and so forth. If you set this to True, you *must* implement the
|
||||
#: detect_managed_devices and debug_managed_device_detection methods.
|
||||
#: A driver with this set to true is responsible for detection of devices,
|
||||
#: managing a blacklist of devices, a list of ejected devices and so forth.
|
||||
#: calibre will periodically call the detect_managed_devices() method and
|
||||
#: is it returns a detected device, calibre will call open(). open() will
|
||||
#: be called every time a device is returned even is previous calls to open()
|
||||
#: failed, therefore the driver must maintain its own blacklist of failed
|
||||
#: devices. Similarly, when ejecting, calibre will call eject() and then
|
||||
#: assuming the next call to detect_managed_devices() returns None, it will
|
||||
#: call post_yank_cleanup().
|
||||
MANAGES_DEVICE_PRESENCE = False
|
||||
|
||||
@classmethod
|
||||
def get_gui_name(cls):
|
||||
@ -196,6 +209,34 @@ class DevicePlugin(Plugin):
|
||||
return True, dev
|
||||
return False, None
|
||||
|
||||
def detect_managed_devices(self, devices_on_system, force_refresh=False):
|
||||
'''
|
||||
Called only if MANAGES_DEVICE_PRESENCE is True.
|
||||
|
||||
Scan for devices that this driver can handle. Should return a device
|
||||
object if a device is found. This object will be passed to the open()
|
||||
method as the connected_device. If no device is found, return None.
|
||||
|
||||
This method is called periodically by the GUI, so make sure it is not
|
||||
too resource intensive. Use a cache to avoid repeatedly scanning the
|
||||
system.
|
||||
|
||||
:param devices_on_system: Set of USB devices found on the system.
|
||||
|
||||
:param force_refresh: If True and the driver uses a cache to prevent
|
||||
repeated scanning, the cache must be flushed.
|
||||
'''
|
||||
raise NotImplementedError()
|
||||
|
||||
def debug_managed_device_detection(self, devices_on_system, output):
|
||||
'''
|
||||
Called only if MANAGES_DEVICE_PRESENCE is True.
|
||||
|
||||
Should write information about the devices detected on the system to
|
||||
output, which is a file like object.
|
||||
'''
|
||||
raise NotImplementedError()
|
||||
|
||||
# }}}
|
||||
|
||||
def reset(self, key='-1', log_packets=False, report_progress=None,
|
||||
|
@ -128,6 +128,10 @@ class DeviceManager(Thread): # {{{
|
||||
self.setDaemon(True)
|
||||
# [Device driver, Showing in GUI, Ejected]
|
||||
self.devices = list(device_plugins())
|
||||
self.managed_devices = [x for x in self.devices if
|
||||
not x.MANAGES_DEVICE_PRESENCE]
|
||||
self.unmanaged_devices = [x for x in self.devices if
|
||||
x.MANAGES_DEVICE_PRESENCE]
|
||||
self.sleep_time = sleep_time
|
||||
self.connected_slot = connected_slot
|
||||
self.jobs = Queue.Queue(0)
|
||||
@ -182,12 +186,15 @@ class DeviceManager(Thread): # {{{
|
||||
prints('Unable to open device', str(dev))
|
||||
prints(tb)
|
||||
continue
|
||||
self.connected_device = dev
|
||||
self.connected_device_kind = device_kind
|
||||
self.connected_slot(True, device_kind)
|
||||
self.after_device_connect(dev, device_kind)
|
||||
return True
|
||||
return False
|
||||
|
||||
def after_device_connect(self, dev, device_kind):
|
||||
self.connected_device = dev
|
||||
self.connected_device_kind = device_kind
|
||||
self.connected_slot(True, device_kind)
|
||||
|
||||
def connected_device_removed(self):
|
||||
while True:
|
||||
try:
|
||||
@ -215,22 +222,45 @@ class DeviceManager(Thread): # {{{
|
||||
|
||||
def detect_device(self):
|
||||
self.scanner.scan()
|
||||
|
||||
if self.is_device_connected:
|
||||
connected, detected_device = \
|
||||
self.scanner.is_device_connected(self.connected_device,
|
||||
only_presence=True)
|
||||
if not connected:
|
||||
if DEBUG:
|
||||
# Allow the device subsystem to output debugging info about
|
||||
# why it thinks the device is not connected. Used, for e.g.
|
||||
# in the can_handle() method of the T1 driver
|
||||
if self.connected_device.MANAGES_DEVICE_PRESENCE:
|
||||
cd = self.connected_device.detect_managed_devices(self.scanner.devices)
|
||||
if cd is None:
|
||||
self.connected_device_removed()
|
||||
else:
|
||||
connected, detected_device = \
|
||||
self.scanner.is_device_connected(self.connected_device,
|
||||
only_presence=True, debug=True)
|
||||
self.connected_device_removed()
|
||||
only_presence=True)
|
||||
if not connected:
|
||||
if DEBUG:
|
||||
# Allow the device subsystem to output debugging info about
|
||||
# why it thinks the device is not connected. Used, for e.g.
|
||||
# in the can_handle() method of the T1 driver
|
||||
self.scanner.is_device_connected(self.connected_device,
|
||||
only_presence=True, debug=True)
|
||||
self.connected_device_removed()
|
||||
else:
|
||||
for dev in self.unmanaged_devices:
|
||||
try:
|
||||
cd = dev.detect_managed_devices(self.scanner.devices)
|
||||
except:
|
||||
prints('Error during device detection for %s:'%dev)
|
||||
traceback.print_exc()
|
||||
else:
|
||||
if cd is not None:
|
||||
try:
|
||||
dev.open(cd, self.current_library_uuid)
|
||||
except:
|
||||
prints('Error while trying to open %s (Driver: %s)'%
|
||||
(cd, dev))
|
||||
traceback.print_exc()
|
||||
else:
|
||||
self.after_device_connect(dev, 'unmanaged-device')
|
||||
return
|
||||
try:
|
||||
possibly_connected_devices = []
|
||||
for device in self.devices:
|
||||
for device in self.managed_devices:
|
||||
if device in self.ejected_devices:
|
||||
continue
|
||||
try:
|
||||
@ -248,7 +278,7 @@ class DeviceManager(Thread): # {{{
|
||||
prints('Connect to device failed, retrying in 5 seconds...')
|
||||
time.sleep(5)
|
||||
if not self.do_connect(possibly_connected_devices,
|
||||
device_kind='usb'):
|
||||
device_kind='device'):
|
||||
if DEBUG:
|
||||
prints('Device connect failed again, giving up')
|
||||
except OpenFailed as e:
|
||||
@ -264,9 +294,10 @@ class DeviceManager(Thread): # {{{
|
||||
# disconnect a device
|
||||
def umount_device(self, *args):
|
||||
if self.is_device_connected and not self.job_manager.has_device_jobs():
|
||||
if self.connected_device_kind == 'device':
|
||||
if self.connected_device_kind in {'unmanaged-device', 'device'}:
|
||||
self.connected_device.eject()
|
||||
self.ejected_devices.add(self.connected_device)
|
||||
if self.connected_device_kind != 'unmanaged-device':
|
||||
self.ejected_devices.add(self.connected_device)
|
||||
self.connected_slot(False, self.connected_device_kind)
|
||||
elif hasattr(self.connected_device, 'unmount_device'):
|
||||
# As we are on the wrong thread, this call must *not* do
|
||||
|
Loading…
x
Reference in New Issue
Block a user