diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py
index a9fc342059..aa6c003114 100644
--- a/src/calibre/customize/builtins.py
+++ b/src/calibre/customize/builtins.py
@@ -165,6 +165,7 @@ class TXTMetadataReader(MetadataReaderPlugin):
name = 'Read TXT metadata'
file_types = set(['txt'])
description = _('Read metadata from %s files') % 'TXT'
+ author = 'John Schember'
def get_metadata(self, stream, ftype):
from calibre.ebooks.metadata.txt import get_metadata
diff --git a/src/calibre/devices/cybookg3/driver.py b/src/calibre/devices/cybookg3/driver.py
index 9e7e9d5862..c3a4fa94b0 100644
--- a/src/calibre/devices/cybookg3/driver.py
+++ b/src/calibre/devices/cybookg3/driver.py
@@ -8,7 +8,7 @@ import os, shutil
from itertools import cycle
from calibre.ebooks.metadata import authors_to_string
-from calibre.devices.errors import FreeSpaceError
+from calibre.devices.errors import DeviceError, FreeSpaceError
from calibre.devices.usbms.driver import USBMS
import calibre.devices.cybookg3.t2b as t2b
@@ -23,28 +23,34 @@ class CYBOOKG3(USBMS):
VENDOR_NAME = 'BOOKEEN'
WINDOWS_MAIN_MEM = 'CYBOOK_GEN3__-FD'
- WINDOWS_CARD_MEM = 'CYBOOK_GEN3__-SD'
+ WINDOWS_CARD_A_MEM = 'CYBOOK_GEN3__-SD'
OSX_MAIN_MEM = 'Bookeen Cybook Gen3 -FD Media'
- OSX_CARD_MEM = 'Bookeen Cybook Gen3 -SD Media'
+ OSX_CARD_A_MEM = 'Bookeen Cybook Gen3 -SD Media'
MAIN_MEMORY_VOLUME_LABEL = 'Cybook Gen 3 Main Memory'
STORAGE_CARD_VOLUME_LABEL = 'Cybook Gen 3 Storage Card'
EBOOK_DIR_MAIN = "eBooks"
- EBOOK_DIR_CARD = "eBooks"
+ EBOOK_DIR_CARD_A = "eBooks"
THUMBNAIL_HEIGHT = 144
SUPPORTS_SUB_DIRS = True
- def upload_books(self, files, names, on_card=False, end_session=True,
+ def upload_books(self, files, names, on_card=None, end_session=True,
metadata=None):
- if on_card and not self._card_prefix:
- raise ValueError(_('The reader has no storage card connected.'))
+ if on_card == 'carda' and not self._card_a_prefix:
+ raise ValueError(_('The reader has no storage card in this slot.'))
+ elif on_card == 'cardb' and not self._card_b_prefix:
+ raise ValueError(_('The reader has no storage card in this slot.'))
+ elif on_card and on_card not in ('carda', 'cardb'):
+ raise DeviceError(_('The reader has no storage card in this slot.'))
- if not on_card:
- path = os.path.join(self._main_prefix, self.EBOOK_DIR_MAIN)
+ if on_card == 'carda':
+ path = os.path.join(self._card_a_prefix, self.EBOOK_DIR_CARD_A)
+ if on_card == 'cardb':
+ path = os.path.join(self._card_b_prefix, self.EBOOK_DIR_CARD_B)
else:
- path = os.path.join(self._card_prefix, self.EBOOK_DIR_CARD)
+ path = os.path.join(self._main_prefix, self.EBOOK_DIR_MAIN)
def get_size(obj):
if hasattr(obj, 'seek'):
@@ -57,10 +63,12 @@ class CYBOOKG3(USBMS):
sizes = [get_size(f) for f in files]
size = sum(sizes)
- if on_card and size > self.free_space()[2] - 1024*1024:
- raise FreeSpaceError(_("There is insufficient free space on the storage card"))
if not on_card and size > self.free_space()[0] - 2*1024*1024:
raise FreeSpaceError(_("There is insufficient free space in main memory"))
+ if on_card == 'carda' and size > self.free_space()[1] - 1024*1024:
+ raise FreeSpaceError(_("There is insufficient free space on the storage card"))
+ if on_card == 'cardb' and size > self.free_space()[2] - 1024*1024:
+ raise FreeSpaceError(_("There is insufficient free space on the storage card"))
paths = []
names = iter(names)
diff --git a/src/calibre/devices/eb600/driver.py b/src/calibre/devices/eb600/driver.py
old mode 100755
new mode 100644
index 44690655a0..cb2f25d2f9
--- a/src/calibre/devices/eb600/driver.py
+++ b/src/calibre/devices/eb600/driver.py
@@ -17,24 +17,24 @@ class EB600(USBMS):
VENDOR_NAME = 'NETRONIX'
WINDOWS_MAIN_MEM = 'EBOOK'
- WINDOWS_CARD_MEM = 'EBOOK'
+ WINDOWS_CARD_A_MEM = 'EBOOK'
OSX_MAIN_MEM = 'EB600 Internal Storage Media'
- OSX_CARD_MEM = 'EB600 Card Storage Media'
+ OSX_CARD_A_MEM = 'EB600 Card Storage Media'
MAIN_MEMORY_VOLUME_LABEL = 'EB600 Main Memory'
STORAGE_CARD_VOLUME_LABEL = 'EB600 Storage Card'
EBOOK_DIR_MAIN = ''
- EBOOK_DIR_CARD = ''
+ EBOOK_DIR_CARD_A = ''
SUPPORTS_SUB_DIRS = True
def windows_sort_drives(self, drives):
main = drives['main']
- card = drives['card']
+ card = drives['carda']
if card and main and card < main:
drives['main'] = card
- drives['card'] = main
+ drives['carda'] = main
return drives
diff --git a/src/calibre/devices/interface.py b/src/calibre/devices/interface.py
index 21790e3c46..0ad01e7493 100644
--- a/src/calibre/devices/interface.py
+++ b/src/calibre/devices/interface.py
@@ -87,7 +87,13 @@ class Device(object):
def card_prefix(self, end_session=True):
'''
- Return prefix to paths on the card or '' if no cards present.
+ Return a 2 element list of the prefix to paths on the cards.
+ If no card is present None is set for the card's prefix.
+ E.G.
+ ('/place', '/place2')
+ (None, 'place2')
+ ('place', None)
+ (None, None)
'''
raise NotImplementedError()
@@ -95,8 +101,8 @@ class Device(object):
"""
Get total space available on the mountpoints:
1. Main memory
- 2. Memory Stick
- 3. SD Card
+ 2. Memory Card A
+ 3. Memory Card B
@return: A 3 element list with total space in bytes of (1, 2, 3). If a
particular device doesn't have any of these locations it should return 0.
@@ -115,24 +121,25 @@ class Device(object):
"""
raise NotImplementedError()
- def books(self, oncard=False, end_session=True):
+ def books(self, oncard=None, end_session=True):
"""
Return a list of ebooks on the device.
- @param oncard: If True return a list of ebooks on the storage card,
- otherwise return list of ebooks in main memory of device.
- If True and no books on card return empty list.
+ @param oncard: If 'carda' or 'cardb' return a list of ebooks on the
+ specific storage card, otherwise return list of ebooks
+ in main memory of device. If a card is specified and no
+ books are on the card return empty list.
@return: A BookList.
"""
raise NotImplementedError()
- def upload_books(self, files, names, on_card=False, end_session=True,
+ def upload_books(self, files, names, on_card=None, end_session=True,
metadata=None):
'''
Upload a list of books to the device. If a file already
exists on the device, it should be replaced.
This method should raise a L{FreeSpaceError} if there is not enough
free space on the device. The text of the FreeSpaceError must contain the
- word "card" if C{on_card} is True otherwise it must contain the word "memory".
+ word "card" if C{on_card} is not None otherwise it must contain the word "memory".
@param files: A list of paths and/or file-like objects.
@param names: A list of file names that the books should have
once uploaded to the device. len(names) == len(files)
@@ -163,7 +170,8 @@ class Device(object):
another dictionary that maps tag names to lists of book ids. The ids are
ids from the book database.
@param booklists: A tuple containing the result of calls to
- (L{books}(oncard=False), L{books}(oncard=True)).
+ (L{books}(oncard=None), L{books}(oncard='carda'),
+ L{books}(oncard='cardb')).
'''
raise NotImplementedError
@@ -179,16 +187,18 @@ class Device(object):
Remove books from the metadata list. This function must not communicate
with the device.
@param paths: paths to books on the device.
- @param booklists: A tuple containing the result of calls to
- (L{books}(oncard=False), L{books}(oncard=True)).
+ @param booklists: A tuple containing the result of calls to
+ (L{books}(oncard=None), L{books}(oncard='carda'),
+ L{books}(oncard='cardb')).
'''
raise NotImplementedError()
def sync_booklists(self, booklists, end_session=True):
'''
Update metadata on device.
- @param booklists: A tuple containing the result of calls to
- (L{books}(oncard=False), L{books}(oncard=True)).
+ @param booklists: A tuple containing the result of calls to
+ (L{books}(oncard=None), L{books}(oncard='carda'),
+ L{books}(oncard='cardb')).
'''
raise NotImplementedError()
diff --git a/src/calibre/devices/kindle/driver.py b/src/calibre/devices/kindle/driver.py
old mode 100755
new mode 100644
index a5775dec8a..d598e2a503
--- a/src/calibre/devices/kindle/driver.py
+++ b/src/calibre/devices/kindle/driver.py
@@ -18,16 +18,16 @@ class KINDLE(USBMS):
VENDOR_NAME = 'KINDLE'
WINDOWS_MAIN_MEM = 'INTERNAL_STORAGE'
- WINDOWS_CARD_MEM = 'CARD_STORAGE'
+ WINDOWS_CARD_A_MEM = 'CARD_STORAGE'
OSX_MAIN_MEM = 'Kindle Internal Storage Media'
- OSX_CARD_MEM = 'Kindle Card Storage Media'
+ OSX_CARD_A_MEM = 'Kindle Card Storage Media'
MAIN_MEMORY_VOLUME_LABEL = 'Kindle Main Memory'
STORAGE_CARD_VOLUME_LABEL = 'Kindle Storage Card'
EBOOK_DIR_MAIN = "documents"
- EBOOK_DIR_CARD = "documents"
+ EBOOK_DIR_CARD_A = "documents"
SUPPORTS_SUB_DIRS = True
WIRELESS_FILE_NAME_PATTERN = re.compile(
diff --git a/src/calibre/devices/prs500/driver.py b/src/calibre/devices/prs500/driver.py
old mode 100755
new mode 100644
diff --git a/src/calibre/devices/prs505/books.py b/src/calibre/devices/prs505/books.py
index eb34bff0e7..3fdb8a8432 100644
--- a/src/calibre/devices/prs505/books.py
+++ b/src/calibre/devices/prs505/books.py
@@ -380,14 +380,16 @@ class BookList(_BookList):
item.setAttribute('id', str(map[id]))
pl.appendChild(item)
-def fix_ids(main, card):
+def fix_ids(main, carda, cardb):
'''
Adjust ids the XML databases.
'''
if hasattr(main, 'purge_empty_playlists'):
main.purge_empty_playlists()
- if hasattr(card, 'purge_empty_playlists'):
- card.purge_empty_playlists()
+ if hasattr(carda, 'purge_empty_playlists'):
+ carda.purge_empty_playlists()
+ if hasattr(cardb, 'purge_empty_playlists'):
+ cardb.purge_empty_playlists()
def regen_ids(db):
if not hasattr(db, 'root_element'):
@@ -413,6 +415,7 @@ def fix_ids(main, card):
db.reorder_playlists()
regen_ids(main)
- regen_ids(card)
+ regen_ids(carda)
+ regen_ids(cardb)
- main.set_next_id(str(main.max_id()+1))
\ No newline at end of file
+ main.set_next_id(str(main.max_id()+1))
diff --git a/src/calibre/devices/prs505/driver.py b/src/calibre/devices/prs505/driver.py
index 6e21c60d1b..efc48a2dff 100644
--- a/src/calibre/devices/prs505/driver.py
+++ b/src/calibre/devices/prs505/driver.py
@@ -6,250 +6,43 @@ Device driver for the SONY PRS-505
import sys, os, shutil, time, subprocess, re
from itertools import cycle
-from calibre.devices.interface import Device
+from calibre.devices.usbms.cli import CLI
+from calibre.devices.usbms.device import Device
from calibre.devices.errors import DeviceError, FreeSpaceError
from calibre.devices.prs505.books import BookList, fix_ids
from calibre import iswindows, islinux, isosx, __appname__
from calibre.devices.errors import PathError
-class File(object):
- def __init__(self, path):
- stats = os.stat(path)
- self.is_dir = os.path.isdir(path)
- self.is_readonly = not os.access(path, os.W_OK)
- self.ctime = stats.st_ctime
- self.wtime = stats.st_mtime
- self.size = stats.st_size
- if path.endswith(os.sep):
- path = path[:-1]
- self.path = path
- self.name = os.path.basename(path)
-
-
-class PRS505(Device):
- VENDOR_ID = 0x054c #: SONY Vendor Id
- PRODUCT_ID = 0x031e #: Product Id for the PRS-505
- BCD = [0x229] #: Needed to disambiguate 505 and 700 on linux
- PRODUCT_NAME = 'PRS-505'
- VENDOR_NAME = 'SONY'
+class PRS505(CLI, Device):
FORMATS = ['epub', 'lrf', 'lrx', 'rtf', 'pdf', 'txt']
+
+ VENDOR_ID = [0x054c] #: SONY Vendor Id
+ PRODUCT_ID = [0x031e] #: Product Id for the PRS-505
+ BCD = [0x229] #: Needed to disambiguate 505 and 700 on linux
- MEDIA_XML = 'database/cache/media.xml'
- CACHE_XML = 'Sony Reader/database/cache.xml'
+ VENDOR_NAME = 'SONY'
+ WINDOWS_MAIN_MEM = 'PRS-505'
+ WINDOWS_CARD_A_MEM = 'PRS-505/UC:MS'
+ WINDOWS_CARD_B_MEM = 'PRS-505/UC:SD'
+
+ OSX_MAIN_MEM = 'Sony PRS-505/UC Media'
+ OSX_CARD_A_MEM = 'Sony PRS-505/UC:MS Media'
+ OSX_CARD_B_MEM = 'Sony PRS-505/UC:SD'
MAIN_MEMORY_VOLUME_LABEL = 'Sony Reader Main Memory'
STORAGE_CARD_VOLUME_LABEL = 'Sony Reader Storage Card'
- OSX_NAME = 'Sony PRS-505'
+ MEDIA_XML = 'database/cache/media.xml'
+ CACHE_XML = 'Sony Reader/database/cache.xml'
CARD_PATH_PREFIX = __appname__
- FDI_TEMPLATE = \
-'''
-
-
-
-
-
-
- %(main_memory)s
- %(deviceclass)s
-
-
-
-
-
-
-
-
-
-
-
-
- %(storage_card)s
- %(deviceclass)s
-
-
-
-
-
-
-'''.replace('%(app)s', __appname__)
-
-
- def __init__(self, log_packets=False):
- self._main_prefix = self._card_prefix = None
-
- @classmethod
- def get_fdi(cls):
- return cls.FDI_TEMPLATE%dict(
- deviceclass=cls.__name__,
- vendor_id=hex(cls.VENDOR_ID),
- product_id=hex(cls.PRODUCT_ID),
- bcd=hex(cls.BCD[0]),
- main_memory=cls.MAIN_MEMORY_VOLUME_LABEL,
- storage_card=cls.STORAGE_CARD_VOLUME_LABEL,
- )
-
- @classmethod
- def is_device(cls, device_id):
- device_id = device_id.upper()
- if 'VEN_'+cls.VENDOR_NAME in device_id and \
- 'PROD_'+cls.PRODUCT_NAME in device_id:
- return True
- vid, pid = hex(cls.VENDOR_ID)[2:], hex(cls.PRODUCT_ID)[2:]
- if len(vid) < 4: vid = '0'+vid
- if len(pid) < 4: pid = '0'+pid
- if 'VID_'+vid in device_id and \
- 'PID_'+pid in device_id:
- return True
- return False
-
- @classmethod
- def get_osx_mountpoints(cls, raw=None):
- if raw is None:
- ioreg = '/usr/sbin/ioreg'
- if not os.access(ioreg, os.X_OK):
- ioreg = 'ioreg'
- raw = subprocess.Popen((ioreg+' -w 0 -S -c IOMedia').split(),
- stdout=subprocess.PIPE).communicate()[0]
- lines = raw.splitlines()
- names = {}
- for i, line in enumerate(lines):
- if line.strip().endswith('') and cls.OSX_NAME in line:
- loc = 'stick' if ':MS' in line else 'card' if ':SD' in line else 'main'
- for line in lines[i+1:]:
- line = line.strip()
- if line.endswith('}'):
- break
- match = re.search(r'"BSD Name"\s+=\s+"(.*?)"', line)
- if match is not None:
- names[loc] = match.group(1)
- break
- if len(names.keys()) == 3:
- break
- return names
-
-
- def open_osx(self):
- mount = subprocess.Popen('mount', shell=True,
- stdout=subprocess.PIPE).stdout.read()
- names = self.get_osx_mountpoints()
- dev_pat = r'/dev/%s(\w*)\s+on\s+([^\(]+)\s+'
- if 'main' not in names.keys():
- raise DeviceError(_('Unable to detect the %s disk drive. Try rebooting.')%self.__class__.__name__)
- main_pat = dev_pat%names['main']
- self._main_prefix = re.search(main_pat, mount).group(2) + os.sep
- card_pat = names['stick'] if 'stick' in names.keys() else names['card'] if 'card' in names.keys() else None
- if card_pat is not None:
- card_pat = dev_pat%card_pat
- self._card_prefix = re.search(card_pat, mount).group(2) + os.sep
-
-
- def open_windows(self):
- time.sleep(6)
- drives = []
- wmi = __import__('wmi', globals(), locals(), [], -1)
- c = wmi.WMI()
- for drive in c.Win32_DiskDrive():
- if self.__class__.is_device(str(drive.PNPDeviceID)):
- if drive.Partitions == 0:
- continue
- try:
- partition = drive.associators("Win32_DiskDriveToDiskPartition")[0]
- logical_disk = partition.associators('Win32_LogicalDiskToPartition')[0]
- prefix = logical_disk.DeviceID+os.sep
- drives.append((drive.Index, prefix))
- except IndexError:
- continue
-
-
- if not drives:
- raise DeviceError(_('Unable to detect the %s disk drive. Try rebooting.')%self.__class__.__name__)
-
- drives.sort(cmp=lambda a, b: cmp(a[0], b[0]))
- self._main_prefix = drives[0][1]
- if len(drives) > 1:
- self._card_prefix = drives[1][1]
-
-
- def open_linux(self):
- import dbus
- bus = dbus.SystemBus()
- hm = dbus.Interface(bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager"), "org.freedesktop.Hal.Manager")
-
- def conditional_mount(dev, main_mem=True):
- mmo = bus.get_object("org.freedesktop.Hal", dev)
- label = mmo.GetPropertyString('volume.label', dbus_interface='org.freedesktop.Hal.Device')
- is_mounted = mmo.GetPropertyString('volume.is_mounted', dbus_interface='org.freedesktop.Hal.Device')
- mount_point = mmo.GetPropertyString('volume.mount_point', dbus_interface='org.freedesktop.Hal.Device')
- fstype = mmo.GetPropertyString('volume.fstype', dbus_interface='org.freedesktop.Hal.Device')
- if is_mounted:
- return str(mount_point)
- mmo.Mount(label, fstype, ['umask=077', 'uid='+str(os.getuid()), 'sync'],
- dbus_interface='org.freedesktop.Hal.Device.Volume')
- return os.path.normpath('/media/'+label)+'/'
-
-
- mm = hm.FindDeviceStringMatch(__appname__+'.mainvolume', self.__class__.__name__)
- if not mm:
- raise DeviceError(_('Unable to detect the %s disk drive. Try rebooting.')%(self.__class__.__name__,))
- self._main_prefix = None
- for dev in mm:
- try:
- self._main_prefix = conditional_mount(dev)+os.sep
- break
- except dbus.exceptions.DBusException:
- continue
-
-
- if not self._main_prefix:
- raise DeviceError('Could not open device for reading. Try a reboot.')
-
- self._card_prefix = None
- cards = hm.FindDeviceStringMatch(__appname__+'.cardvolume', self.__class__.__name__)
- keys = []
- for card in cards:
- keys.append(int('UC_SD' in bus.get_object("org.freedesktop.Hal", card).GetPropertyString('info.parent', dbus_interface='org.freedesktop.Hal.Device')))
-
- cards = zip(cards, keys)
- cards.sort(cmp=lambda x, y: cmp(x[1], y[1]))
- cards = [i[0] for i in cards]
-
- for dev in cards:
- try:
- self._card_prefix = conditional_mount(dev, False)+os.sep
- break
- except:
- import traceback
- print traceback
- continue
-
-
def open(self):
- time.sleep(5)
- self._main_prefix = self._card_prefix = None
- if islinux:
+ Device.open(self)
+
+ def write_cache(prefix):
try:
- self.open_linux()
- except DeviceError:
- time.sleep(3)
- self.open_linux()
- if iswindows:
- try:
- self.open_windows()
- except DeviceError:
- time.sleep(3)
- self.open_windows()
- if isosx:
- try:
- self.open_osx()
- except DeviceError:
- time.sleep(3)
- self.open_osx()
- if self._card_prefix is not None:
- try:
- cachep = os.path.join(self._card_prefix, self.CACHE_XML)
+ cachep = os.path.join(prefix, self.CACHE_XML)
if not os.path.exists(cachep):
os.makedirs(os.path.dirname(cachep), mode=0777)
f = open(cachep, 'wb')
@@ -263,133 +56,47 @@ class PRS505(Device):
import traceback
traceback.print_exc()
- def set_progress_reporter(self, pr):
- self.report_progress = pr
+ if self._card_a_prefix is not None:
+ write_cache(self._card_a_prefix)
+ if self._card_b_prefix is not None:
+ write_cache(self._card_b_prefix)
def get_device_information(self, end_session=True):
return (self.__class__.__name__, '', '', '')
- def card_prefix(self, end_session=True):
- return self._card_prefix
-
- @classmethod
- def _windows_space(cls, prefix):
- if prefix is None:
- return 0, 0
- win32file = __import__('win32file', globals(), locals(), [], -1)
- try:
- sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters = \
- win32file.GetDiskFreeSpace(prefix[:-1])
- except Exception, err:
- if getattr(err, 'args', [None])[0] == 21: # Disk not ready
- time.sleep(3)
- sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters = \
- win32file.GetDiskFreeSpace(prefix[:-1])
- else: raise
- mult = sectors_per_cluster * bytes_per_sector
- return total_clusters * mult, free_clusters * mult
-
- def total_space(self, end_session=True):
- msz = csz = 0
- if not iswindows:
- if self._main_prefix is not None:
- stats = os.statvfs(self._main_prefix)
- msz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree)
- if self._card_prefix is not None:
- stats = os.statvfs(self._card_prefix)
- csz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree)
- else:
- msz = self._windows_space(self._main_prefix)[0]
- csz = self._windows_space(self._card_prefix)[0]
-
- return (msz, 0, csz)
-
- def free_space(self, end_session=True):
- msz = csz = 0
- if not iswindows:
- if self._main_prefix is not None:
- stats = os.statvfs(self._main_prefix)
- msz = stats.f_frsize * stats.f_bavail
- if self._card_prefix is not None:
- stats = os.statvfs(self._card_prefix)
- csz = stats.f_frsize * stats.f_bavail
- else:
- msz = self._windows_space(self._main_prefix)[1]
- csz = self._windows_space(self._card_prefix)[1]
-
- return (msz, 0, csz)
-
- def books(self, oncard=False, end_session=True):
- if oncard and self._card_prefix is None:
+ def books(self, oncard=None, end_session=True):
+ if oncard == 'carda' and not self._card_a_prefix:
return []
+ elif oncard == 'cardb' and not self._card_b_prefix:
+ return []
+ elif oncard and oncard != 'carda' and oncard != 'cardb':
+ return []
+
db = self.__class__.CACHE_XML if oncard else self.__class__.MEDIA_XML
- prefix = self._card_prefix if oncard else self._main_prefix
+ prefix = self._card_a_prefix if oncard == 'carda' else self._card_b_prefix if oncard == 'cardb' else self._main_prefix
bl = BookList(open(prefix + db, 'rb'), prefix)
paths = bl.purge_corrupted_files()
for path in paths:
- path = os.path.join(self._card_prefix if oncard else self._main_prefix, path)
+ path = os.path.join(prefix, path)
if os.path.exists(path):
os.unlink(path)
return bl
- def munge_path(self, path):
- if path.startswith('/') and not (path.startswith(self._main_prefix) or \
- (self._card_prefix and path.startswith(self._card_prefix))):
- path = self._main_prefix + path[1:]
- elif path.startswith('card:'):
- path = path.replace('card:', self._card_prefix[:-1])
- return path
-
- def mkdir(self, path, end_session=True):
- """ Make directory """
- path = self.munge_path(path)
- os.mkdir(path)
-
- def list(self, path, recurse=False, end_session=True, munge=True):
- if munge:
- path = self.munge_path(path)
- if os.path.isfile(path):
- return [(os.path.dirname(path), [File(path)])]
- entries = [File(os.path.join(path, f)) for f in os.listdir(path)]
- dirs = [(path, entries)]
- for _file in entries:
- if recurse and _file.is_dir:
- dirs[len(dirs):] = self.list(_file.path, recurse=True, munge=False)
- return dirs
-
- def get_file(self, path, outfile, end_session=True):
- path = self.munge_path(path)
- src = open(path, 'rb')
- shutil.copyfileobj(src, outfile, 10*1024*1024)
-
- def put_file(self, infile, path, replace_file=False, end_session=True):
- path = self.munge_path(path)
- if os.path.isdir(path):
- path = os.path.join(path, infile.name)
- if not replace_file and os.path.exists(path):
- raise PathError('File already exists: '+path)
- dest = open(path, 'wb')
- shutil.copyfileobj(infile, dest, 10*1024*1024)
- dest.flush()
- dest.close()
-
- def rm(self, path, end_session=True):
- path = self.munge_path(path)
- os.unlink(path)
-
- def touch(self, path, end_session=True):
- path = self.munge_path(path)
- if not os.path.exists(path):
- open(path, 'w').close()
- if not os.path.isdir(path):
- os.utime(path, None)
-
- def upload_books(self, files, names, on_card=False, end_session=True,
+ def upload_books(self, files, names, on_card=None, end_session=True,
metadata=None):
- if on_card and not self._card_prefix:
- raise ValueError(_('The reader has no storage card connected.'))
- path = os.path.join(self._card_prefix, self.CARD_PATH_PREFIX) if on_card \
- else os.path.join(self._main_prefix, 'database', 'media', 'books')
+ if on_card == 'carda' and not self._card_a_prefix:
+ raise ValueError(_('The reader has no storage card in this slot.'))
+ elif on_card == 'cardb' and not self._card_b_prefix:
+ raise ValueError(_('The reader has no storage card in this slot.'))
+ elif on_card and on_card not in ('carda', 'cardb'):
+ raise DeviceError(_('The reader has no storage card in this slot.'))
+
+ if on_card == 'carda':
+ path = os.path.join(self._card_a_prefix, self.CARD_PATH_PREFIX)
+ elif on_card == 'cardb':
+ path = os.path.join(self._card_b_prefix, self.CARD_PATH_PREFIX)
+ else:
+ path = os.path.join(self._main_prefix, 'database', 'media', 'books')
def get_size(obj):
if hasattr(obj, 'seek'):
@@ -399,17 +106,15 @@ class PRS505(Device):
return size
return os.path.getsize(obj)
- sizes = map(get_size, files)
+ sizes = [get_size(f) for f in files]
size = sum(sizes)
- space = self.free_space()
- mspace = space[0]
- cspace = space[2]
- if on_card and size > cspace - 1024*1024:
- raise FreeSpaceError("There is insufficient free space "+\
- "on the storage card")
- if not on_card and size > mspace - 2*1024*1024:
- raise FreeSpaceError("There is insufficient free space " +\
- "in main memory")
+
+ if not on_card and size > self.free_space()[0] - 2*1024*1024:
+ raise FreeSpaceError(_("There is insufficient free space in main memory"))
+ if on_card == 'carda' and size > self.free_space()[1] - 1024*1024:
+ raise FreeSpaceError(_("There is insufficient free space on the storage card"))
+ if on_card == 'cardb' and size > self.free_space()[2] - 1024*1024:
+ raise FreeSpaceError(_("There is insufficient free space on the storage card"))
paths, ctimes = [], []
@@ -435,11 +140,11 @@ class PRS505(Device):
for location in locations:
info = metadata.next()
path = location[0]
- on_card = 1 if location[3] else 0
+ blist = 2 if location[3] == 'cardb' else 1 if location[3] == 'carda' else 0
name = path.rpartition(os.sep)[2]
- name = (cls.CARD_PATH_PREFIX+'/' if on_card else 'database/media/books/') + name
+ name = (cls.CARD_PATH_PREFIX+'/' if blist else 'database/media/books/') + name
name = name.replace('//', '/')
- booklists[on_card].add_book(info, name, *location[1:-1])
+ booklists[blist].add_book(info, name, *location[1:-1])
fix_ids(*booklists)
def delete_books(self, paths, end_session=True):
@@ -462,18 +167,13 @@ class PRS505(Device):
f = open(self._main_prefix + self.__class__.MEDIA_XML, 'wb')
booklists[0].write(f)
f.close()
- if self._card_prefix is not None and hasattr(booklists[1], 'write'):
- if not os.path.exists(self._card_prefix):
- os.makedirs(self._card_prefix)
- f = open(self._card_prefix + self.__class__.CACHE_XML, 'wb')
- booklists[1].write(f)
- f.close()
-
-
-
-
-def main(args=sys.argv):
- return 0
-
-if __name__ == '__main__':
- sys.exit(main())
+
+ def write_card_prefix(prefix, listid):
+ if prefix is not None and hasattr(booklists[listid], 'write'):
+ if not os.path.exists(prefix):
+ os.makedirs(prefix)
+ f = open(prefix + self.__class__.CACHE_XML, 'wb')
+ booklists[listid].write(f)
+ f.close()
+ write_card_prefix(self._card_a_prefix, 1)
+ write_card_prefix(self._card_b_prefix, 2)
diff --git a/src/calibre/devices/prs700/driver.py b/src/calibre/devices/prs700/driver.py
index 5db60ef506..2b82eb3e34 100644
--- a/src/calibre/devices/prs700/driver.py
+++ b/src/calibre/devices/prs700/driver.py
@@ -10,6 +10,12 @@ from calibre.devices.prs505.driver import PRS505
class PRS700(PRS505):
BCD = [0x31a]
- PRODUCT_NAME = 'PRS-700'
- OSX_NAME = 'Sony PRS-700'
-
+
+ WINDOWS_MAIN_MEM = 'PRS-700'
+ WINDOWS_CARD_A_MEM = 'PRS-700/UC:MS'
+ WINDOWS_CARD_B_MEM = 'PRS-700/UC:SD'
+
+ OSX_MAIN_MEM = 'Sony PRS-700/UC Media'
+ OSX_CARD_A_MEM = 'Sony PRS-700/UC:MS Media'
+ OSX_CARD_B_MEM = 'Sony PRS-700/UC:SD'
+
diff --git a/src/calibre/devices/usbms/cli.py b/src/calibre/devices/usbms/cli.py
new file mode 100644
index 0000000000..40e2225486
--- /dev/null
+++ b/src/calibre/devices/usbms/cli.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+from __future__ import with_statement
+
+__license__ = 'GPL 3'
+__copyright__ = '2009, John Schember '
+__docformat__ = 'restructuredtext en'
+
+import os, shutil
+
+from calibre.devices.errors import PathError
+
+class File(object):
+
+ def __init__(self, path):
+ stats = os.stat(path)
+ self.is_dir = os.path.isdir(path)
+ self.is_readonly = not os.access(path, os.W_OK)
+ self.ctime = stats.st_ctime
+ self.wtime = stats.st_mtime
+ self.size = stats.st_size
+ if path.endswith(os.sep):
+ path = path[:-1]
+ self.path = path
+ self.name = os.path.basename(path)
+
+
+class CLI(object):
+
+ def get_file(self, path, outfile, end_session=True):
+ path = self.munge_path(path)
+ with open(path, 'rb') as src:
+ shutil.copyfileobj(src, outfile, 10*1024*1024)
+
+ def put_file(self, infile, path, replace_file=False, end_session=True):
+ path = self.munge_path(path)
+ if os.path.isdir(path):
+ path = os.path.join(path, infile.name)
+ if not replace_file and os.path.exists(path):
+ raise PathError('File already exists: ' + path)
+ dest = open(path, 'wb')
+ shutil.copyfileobj(infile, dest, 10*1024*1024)
+ dest.flush()
+ dest.close()
+
+ def munge_path(self, path):
+ if path.startswith('/') and not (path.startswith(self._main_prefix) or \
+ (self._card_a_prefix and path.startswith(self._card_a_prefix)) or \
+ (self._card_b_prefix and path.startswith(self._card_b_prefix))):
+ path = self._main_prefix + path[1:]
+ elif path.startswith('carda:'):
+ path = path.replace('carda:', self._card_prefix[:-1])
+ elif path.startswith('cardb:'):
+ path = path.replace('cardb:', self._card_prefix[:-1])
+ return path
+
+ def list(self, path, recurse=False, end_session=True, munge=True):
+ if munge:
+ path = self.munge_path(path)
+ if os.path.isfile(path):
+ return [(os.path.dirname(path), [File(path)])]
+ entries = [File(os.path.join(path, f)) for f in os.listdir(path)]
+ dirs = [(path, entries)]
+ for _file in entries:
+ if recurse and _file.is_dir:
+ dirs[len(dirs):] = self.list(_file.path, recurse=True, munge=False)
+ return dirs
+
+ def mkdir(self, path, end_session=True):
+ if self.SUPPORTS_SUB_DIRS:
+ path = self.munge_path(path)
+ os.mkdir(path)
+
+ def rm(self, path, end_session=True):
+ path = self.munge_path(path)
+ self.delete_books([path])
+
+ def touch(self, path, end_session=True):
+ path = self.munge_path(path)
+ if not os.path.exists(path):
+ open(path, 'w').close()
+ if not os.path.isdir(path):
+ os.utime(path, None)
diff --git a/src/calibre/devices/usbms/device.py b/src/calibre/devices/usbms/device.py
index 5a1b5ef40d..63dabe001a 100644
--- a/src/calibre/devices/usbms/device.py
+++ b/src/calibre/devices/usbms/device.py
@@ -25,10 +25,12 @@ class Device(_Device):
VENDOR_NAME = None
WINDOWS_MAIN_MEM = None
- WINDOWS_CARD_MEM = None
+ WINDOWS_CARD_A_MEM = None
+ WINDOWS_CARD_B_MEM = None
OSX_MAIN_MEM = None
- OSX_CARD_MEM = None
+ OSX_CARD_A_MEM = None
+ OSX_CARD_B_MEM = None
MAIN_MEMORY_VOLUME_LABEL = ''
STORAGE_CARD_VOLUME_LABEL = ''
@@ -63,12 +65,26 @@ class Device(_Device):
+
+
+
+
+ %(BCD_start)s
+
+ %(storage_card)s
+ %(deviceclass)s
+
+ %(BCD_end)s
+
+
+
+
'''
FDI_BCD_TEMPLATE = ''
def __init__(self, key='-1', log_packets=False, report_progress=None) :
- self._main_prefix = self._card_prefix = None
+ self._main_prefix = self._card_a_prefix = self._card_b_prefix = None
@classmethod
def get_fdi(cls):
@@ -102,7 +118,7 @@ class Device(_Device):
self.report_progress = report_progress
def card_prefix(self, end_session=True):
- return self._card_prefix
+ return (self._card_a_prefix, self._card_b_prefix)
@classmethod
def _windows_space(cls, prefix):
@@ -122,34 +138,41 @@ class Device(_Device):
return total_clusters * mult, free_clusters * mult
def total_space(self, end_session=True):
- msz = csz = 0
+ msz = casz = cbsz = 0
if not iswindows:
if self._main_prefix is not None:
stats = os.statvfs(self._main_prefix)
msz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree)
- if self._card_prefix is not None:
- stats = os.statvfs(self._card_prefix)
- csz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree)
+ if self._card_a_prefix is not None:
+ stats = os.statvfs(self._card_a_prefix)
+ casz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree)
+ if self._card_b_prefix is not None:
+ stats = os.statvfs(self._card_b_prefix)
+ cbsz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree)
else:
msz = self._windows_space(self._main_prefix)[0]
- csz = self._windows_space(self._card_prefix)[0]
+ casz = self._windows_space(self._card_a_prefix)[0]
+ cbsz = self._windows_space(self._card_b_prefix)[0]
- return (msz, 0, csz)
+ return (msz, casz, cbsz)
def free_space(self, end_session=True):
- msz = csz = 0
+ msz = casz = cbsz = 0
if not iswindows:
if self._main_prefix is not None:
stats = os.statvfs(self._main_prefix)
msz = stats.f_frsize * stats.f_bavail
- if self._card_prefix is not None:
- stats = os.statvfs(self._card_prefix)
- csz = stats.f_frsize * stats.f_bavail
+ if self._card_a_prefix is not None:
+ stats = os.statvfs(self._card_a_prefix)
+ casz = stats.f_frsize * stats.f_bavail
+ if self._card_b_prefix is not None:
+ stats = os.statvfs(self._card_b_prefix)
+ cbsz = stats.f_frsize * stats.f_bavail
else:
msz = self._windows_space(self._main_prefix)[1]
csz = self._windows_space(self._card_prefix)[1]
- return (msz, 0, csz)
+ return (msz, casz, cbsz)
def windows_match_device(self, pnp_id, device_id):
pnp_id = pnp_id.upper()
@@ -190,15 +213,18 @@ class Device(_Device):
for drive in c.Win32_DiskDrive():
if self.windows_match_device(str(drive.PNPDeviceID), self.WINDOWS_MAIN_MEM):
drives['main'] = self.windows_get_drive_prefix(drive)
- elif self.windows_match_device(str(drive.PNPDeviceID), self.WINDOWS_CARD_MEM):
- drives['card'] = self.windows_get_drive_prefix(drive)
+ elif self.windows_match_device(str(drive.PNPDeviceID), self.WINDOWS_CARD_A_MEM):
+ drives['carda'] = self.windows_get_drive_prefix(drive)
+ elif self.windows_match_device(str(drive.PNPDeviceID), self.WINDOWS_CARD_B_MEM):
+ drives['cardb'] = self.windows_get_drive_prefix(drive)
- if 'main' in drives.keys() and 'card' in drives.keys():
+ if 'main' in drives.keys() and 'carda' in drives.keys() and 'cardb' in drives.keys():
break
drives = self.windows_sort_drives(drives)
self._main_prefix = drives.get('main')
- self._card_prefix = drives.get('card')
+ self._card_a_prefix = drives.get('carda')
+ self._card_b_prefix = drives.get('cardb')
if not self._main_prefix:
raise DeviceError(
@@ -228,9 +254,11 @@ class Device(_Device):
for i, line in enumerate(lines):
if self.OSX_MAIN_MEM is not None and line.strip().endswith('') and self.OSX_MAIN_MEM in line:
get_dev_node(lines[i+1:], 'main')
- if self.OSX_CARD_MEM is not None and line.strip().endswith('') and self.OSX_CARD_MEM in line:
- get_dev_node(lines[i+1:], 'card')
- if len(names.keys()) == 2:
+ if self.OSX_CARD_A_MEM is not None and line.strip().endswith('') and self.OSX_CARD_A_MEM in line:
+ get_dev_node(lines[i+1:], 'carda')
+ if self.OSX_CARD_B_MEM is not None and line.strip().endswith('') and self.OSX_CARD_B_MEM in line:
+ get_dev_node(lines[i+1:], 'cardb')
+ if len(names.keys()) == 3:
break
return names
@@ -242,10 +270,18 @@ class Device(_Device):
raise DeviceError(_('Unable to detect the %s disk drive. Try rebooting.')%self.__class__.__name__)
main_pat = dev_pat % names['main']
self._main_prefix = re.search(main_pat, mount).group(2) + os.sep
- card_pat = names['card'] if 'card' in names.keys() else None
- if card_pat is not None:
- card_pat = dev_pat % card_pat
- self._card_prefix = re.search(card_pat, mount).group(2) + os.sep
+ card_a_pat = names['carda'] if 'carda' in names.keys() else None
+ card_b_pat = names['cardb'] if 'cardb' in names.keys() else None
+
+ def get_card_prefix(pat):
+ if pat is not None:
+ pat = dev_pat % pat
+ return re.search(pat, mount).group(2) + os.sep
+ else:
+ return None
+
+ self._card_a_prefix = get_card_prefix(card_a_pat)
+ self._card_b_prefix = get_card_prefix(card_b_pat)
def open_linux(self):
import dbus
@@ -278,21 +314,24 @@ class Device(_Device):
if not self._main_prefix:
raise DeviceError('Could not open device for reading. Try a reboot.')
- self._card_prefix = None
+ self._card_a_prefix = self._card_b_prefix = None
cards = hm.FindDeviceStringMatch(__appname__+'.cardvolume', self.__class__.__name__)
- for dev in cards:
+ def mount_card(dev):
try:
- self._card_prefix = conditional_mount(dev)+os.sep
- break
+ return conditional_mount(dev)+os.sep
except:
import traceback
print traceback
- continue
+
+ if len(cards) >= 1:
+ self._card_a_prefix = mount_card(cards[0])
+ if len(cards) >=2:
+ self._card_b_prefix = mount_card(cards[1])
def open(self):
time.sleep(5)
- self._main_prefix = self._card_prefix = None
+ self._main_prefix = self._card_a_prefix = self._card_b_prefix = None
if islinux:
try:
self.open_linux()
diff --git a/src/calibre/devices/usbms/driver.py b/src/calibre/devices/usbms/driver.py
index 0a66b78014..bb7a104fa4 100644
--- a/src/calibre/devices/usbms/driver.py
+++ b/src/calibre/devices/usbms/driver.py
@@ -12,28 +12,19 @@ from itertools import cycle
from calibre.ebooks.metadata.meta import metadata_from_formats, path_to_ext
from calibre.ebooks.metadata import authors_to_string
+from calibre.devices.usbms.cli import CLI
from calibre.devices.usbms.device import Device
from calibre.devices.usbms.books import BookList, Book
-from calibre.devices.errors import FreeSpaceError, PathError
+from calibre.devices.errors import DeviceError, FreeSpaceError
from calibre.devices.mime import mime_type_ext
-class File(object):
- def __init__(self, path):
- stats = os.stat(path)
- self.is_dir = os.path.isdir(path)
- self.is_readonly = not os.access(path, os.W_OK)
- self.ctime = stats.st_ctime
- self.wtime = stats.st_mtime
- self.size = stats.st_size
- if path.endswith(os.sep):
- path = path[:-1]
- self.path = path
- self.name = os.path.basename(path)
-
-class USBMS(Device):
+# CLI must come before Device as it implments the CLI functions that
+# are inherited from the device interface in Device.
+class USBMS(CLI, Device):
FORMATS = []
EBOOK_DIR_MAIN = ''
- EBOOK_DIR_CARD = ''
+ EBOOK_DIR_CARD_A = ''
+ EBOOK_DIR_CARD_B = ''
SUPPORTS_SUB_DIRS = False
CAN_SET_METADATA = False
@@ -48,14 +39,18 @@ class USBMS(Device):
"""
return (self.__class__.__name__, '', '', '')
- def books(self, oncard=False, end_session=True):
+ def books(self, oncard=None, end_session=True):
bl = BookList()
- if oncard and self._card_prefix is None:
+ if oncard == 'carda' and not self._card_a_prefix:
+ return bl
+ elif oncard == 'cardb' and not self._card_b_prefix:
+ return bl
+ elif oncard and oncard != 'carda' and oncard != 'cardb':
return bl
- prefix = self._card_prefix if oncard else self._main_prefix
- ebook_dir = self.EBOOK_DIR_CARD if oncard else self.EBOOK_DIR_MAIN
+ prefix = self._card_a_prefix if oncard == 'carda' else self._card_b_prefix if oncard == 'cardb' else self._main_prefix
+ ebook_dir = self.EBOOK_DIR_CARD_A if oncard == 'carda' else self.EBOOK_DIR_CARD_B if oncard == 'cardb' else self.EBOOK_DIR_MAIN
# Get all books in the ebook_dir directory
if self.SUPPORTS_SUB_DIRS:
@@ -71,15 +66,21 @@ class USBMS(Device):
bl.append(self.__class__.book_from_path(os.path.join(path, filename)))
return bl
- def upload_books(self, files, names, on_card=False, end_session=True,
+ def upload_books(self, files, names, on_card=None, end_session=True,
metadata=None):
- if on_card and not self._card_prefix:
- raise ValueError(_('The reader has no storage card connected.'))
+ if on_card == 'carda' and not self._card_a_prefix:
+ raise ValueError(_('The reader has no storage card in this slot.'))
+ elif on_card == 'cardb' and not self._card_b_prefix:
+ raise ValueError(_('The reader has no storage card in this slot.'))
+ elif on_card and on_card not in ('carda', 'cardb'):
+ raise DeviceError(_('The reader has no storage card in this slot.'))
- if not on_card:
- path = os.path.join(self._main_prefix, self.EBOOK_DIR_MAIN)
+ if on_card == 'carda':
+ path = os.path.join(self._card_a_prefix, self.EBOOK_DIR_CARD_A)
+ if on_card == 'cardb':
+ path = os.path.join(self._card_b_prefix, self.EBOOK_DIR_CARD_B)
else:
- path = os.path.join(self._card_prefix, self.EBOOK_DIR_CARD)
+ path = os.path.join(self._main_prefix, self.EBOOK_DIR_MAIN)
def get_size(obj):
if hasattr(obj, 'seek'):
@@ -92,10 +93,12 @@ class USBMS(Device):
sizes = [get_size(f) for f in files]
size = sum(sizes)
- if on_card and size > self.free_space()[2] - 1024*1024:
- raise FreeSpaceError(_("There is insufficient free space on the storage card"))
if not on_card and size > self.free_space()[0] - 2*1024*1024:
raise FreeSpaceError(_("There is insufficient free space in main memory"))
+ if on_card == 'carda' and size > self.free_space()[1] - 1024*1024:
+ raise FreeSpaceError(_("There is insufficient free space on the storage card"))
+ if on_card == 'cardb' and size > self.free_space()[2] - 1024*1024:
+ raise FreeSpaceError(_("There is insufficient free space on the storage card"))
paths = []
names = iter(names)
@@ -147,12 +150,12 @@ class USBMS(Device):
def add_books_to_metadata(cls, locations, metadata, booklists):
for location in locations:
path = location[0]
- on_card = 1 if location[1] else 0
+ blist = 2 if location[1] == 'cardb' else 1 if location[1] == 'carda' else 0
book = cls.book_from_path(path)
- if not book in booklists[on_card]:
- booklists[on_card].append(book)
+ if not book in booklists[blist]:
+ booklists[blist].append(book)
def delete_books(self, paths, end_session=True):
@@ -180,58 +183,6 @@ class USBMS(Device):
# the Sony Readers.
pass
- def get_file(self, path, outfile, end_session=True):
- path = self.munge_path(path)
- with open(path, 'rb') as src:
- shutil.copyfileobj(src, outfile, 10*1024*1024)
-
- def put_file(self, infile, path, replace_file=False, end_session=True):
- path = self.munge_path(path)
- if os.path.isdir(path):
- path = os.path.join(path, infile.name)
- if not replace_file and os.path.exists(path):
- raise PathError('File already exists: ' + path)
- dest = open(path, 'wb')
- shutil.copyfileobj(infile, dest, 10*1024*1024)
- dest.flush()
- dest.close()
-
- def munge_path(self, path):
- if path.startswith('/') and not (path.startswith(self._main_prefix) or \
- (self._card_prefix and path.startswith(self._card_prefix))):
- path = self._main_prefix + path[1:]
- elif path.startswith('card:'):
- path = path.replace('card:', self._card_prefix[:-1])
- return path
-
- def list(self, path, recurse=False, end_session=True, munge=True):
- if munge:
- path = self.munge_path(path)
- if os.path.isfile(path):
- return [(os.path.dirname(path), [File(path)])]
- entries = [File(os.path.join(path, f)) for f in os.listdir(path)]
- dirs = [(path, entries)]
- for _file in entries:
- if recurse and _file.is_dir:
- dirs[len(dirs):] = self.list(_file.path, recurse=True, munge=False)
- return dirs
-
- def mkdir(self, path, end_session=True):
- if self.SUPPORTS_SUB_DIRS:
- path = self.munge_path(path)
- os.mkdir(path)
-
- def rm(self, path, end_session=True):
- path = self.munge_path(path)
- self.delete_books([path])
-
- def touch(self, path, end_session=True):
- path = self.munge_path(path)
- if not os.path.exists(path):
- open(path, 'w').close()
- if not os.path.isdir(path):
- os.utime(path, None)
-
@classmethod
def metadata_from_path(cls, path):
return metadata_from_formats([path])
diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py
index c2a61e7648..201ab02dd1 100644
--- a/src/calibre/gui2/device.py
+++ b/src/calibre/gui2/device.py
@@ -139,9 +139,10 @@ class DeviceManager(Thread):
def _books(self):
'''Get metadata from device'''
- mainlist = self.device.books(oncard=False, end_session=False)
- cardlist = self.device.books(oncard=True)
- return (mainlist, cardlist)
+ mainlist = self.device.books(oncard=None, end_session=False)
+ cardalist = self.device.books(oncard='carda')
+ cardblist = self.device.books(oncard='cardb')
+ return (mainlist, cardalist, cardblist)
def books(self, done):
'''Return callable that returns the list of books on device as two booklists'''
@@ -156,12 +157,12 @@ class DeviceManager(Thread):
return self.create_job(self._sync_booklists, done, args=[booklists],
description=_('Send metadata to device'))
- def _upload_books(self, files, names, on_card=False, metadata=None):
+ def _upload_books(self, files, names, on_card=None, metadata=None):
'''Upload books to device: '''
return self.device.upload_books(files, names, on_card,
metadata=metadata, end_session=False)
- def upload_books(self, done, files, names, on_card=False, titles=None,
+ def upload_books(self, done, files, names, on_card=None, titles=None,
metadata=None):
desc = _('Upload %d books to device')%len(names)
if titles:
@@ -197,6 +198,7 @@ class DeviceManager(Thread):
def _view_book(self, path, target):
f = open(target, 'wb')
+ print self.device
self.device.get_file(path, f)
f.close()
return target
@@ -256,24 +258,27 @@ class DeviceMenu(QMenu):
self.connect(action2, SIGNAL('a_s(QAction)'),
self.action_triggered)
-
-
-
_actions = [
('main:', False, False, ':/images/reader.svg',
_('Send to main memory')),
- ('card:0', False, False, ':/images/sd.svg',
- _('Send to storage card')),
+ ('carda:0', False, False, ':/images/sd.svg',
+ _('Send to storage card A')),
+ ('cardb:0', False, False, ':/images/sd.svg',
+ _('Send to storage card B')),
'-----',
('main:', True, False, ':/images/reader.svg',
_('Send to main memory')),
- ('card:0', True, False, ':/images/sd.svg',
- _('Send to storage card')),
+ ('carda:0', True, False, ':/images/sd.svg',
+ _('Send to storage card A')),
+ ('cardb:0', True, False, ':/images/sd.svg',
+ _('Send to storage card B')),
'-----',
('main:', False, True, ':/images/reader.svg',
_('Send specific format to main memory')),
- ('card:0', False, True, ':/images/sd.svg',
- _('Send specific format to storage card')),
+ ('carda:0', False, True, ':/images/sd.svg',
+ _('Send specific format to storage card A')),
+ ('cardb:0', False, True, ':/images/sd.svg',
+ _('Send specific format to storage card B')),
]
if default_account is not None:
@@ -335,7 +340,7 @@ class DeviceMenu(QMenu):
def enable_device_actions(self, enable):
for action in self.actions:
- if action.dest[:4] in ('main', 'card'):
+ if action.dest in ('main:', 'carda:0', 'cardb:0'):
action.setEnabled(enable)
class Emailer(Thread):
@@ -412,16 +417,23 @@ class DeviceGUI(object):
d.exec_()
fmt = d.format().lower()
dest, sub_dest = dest.split(':')
- if dest in ('main', 'card'):
+ if dest in ('main', 'carda', 'cardb'):
if not self.device_connected or not self.device_manager:
error_dialog(self, _('No device'),
_('Cannot send: No device is connected')).exec_()
return
- on_card = dest == 'card'
- if on_card and not self.device_manager.has_card():
+ if dest == 'carda' and not self.device_manager.has_card():
error_dialog(self, _('No card'),
_('Cannot send: Device has no storage card')).exec_()
return
+ if dest == 'cardb' and not self.device_manager.has_card():
+ error_dialog(self, _('No card'),
+ _('Cannot send: Device has no storage card')).exec_()
+ return
+ if dest == 'main':
+ on_card = None
+ else:
+ on_card = dest
self.sync_to_device(on_card, delete, fmt)
elif dest == 'mail':
to, fmts = sub_dest.split(';')
@@ -680,7 +692,7 @@ class DeviceGUI(object):
cp, fs = job.result
self.location_view.model().update_devices(cp, fs)
- def upload_books(self, files, names, metadata, on_card=False, memory=None):
+ def upload_books(self, files, names, metadata, on_card=None, memory=None):
'''
Upload books to device.
:param files: List of either paths to files or file like objects
@@ -719,7 +731,7 @@ class DeviceGUI(object):
self.upload_booklists()
- view = self.card_view if on_card else self.memory_view
+ view = self.card_a_view if on_card == 'carda' else self.card_b_view if on_card == 'cardb' else self.memory_view
view.model().resort(reset=False)
view.model().research()
for f in files:
diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py
index b198814c93..86d1b013e3 100644
--- a/src/calibre/gui2/main.py
+++ b/src/calibre/gui2/main.py
@@ -305,7 +305,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
similar_menu=similar_menu)
self.memory_view.set_context_menu(None, None, None,
self.action_view, self.action_save, None, None)
- self.card_view.set_context_menu(None, None, None,
+ self.card_a_view.set_context_menu(None, None, None,
+ self.action_view, self.action_save, None, None)
+ self.card_b_view.set_context_menu(None, None, None,
self.action_view, self.action_save, None, None)
QObject.connect(self.library_view,
SIGNAL('files_dropped(PyQt_PyObject)'),
@@ -315,11 +317,12 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
('connect_to_book_display',
self.status_bar.book_info.show_data),
]:
- for view in (self.library_view, self.memory_view, self.card_view):
+ for view in (self.library_view, self.memory_view, self.card_a_view, self.card_b_view):
getattr(view, func)(target)
self.memory_view.connect_dirtied_signal(self.upload_booklists)
- self.card_view.connect_dirtied_signal(self.upload_booklists)
+ self.card_a_view.connect_dirtied_signal(self.upload_booklists)
+ self.card_b_view.connect_dirtied_signal(self.upload_booklists)
self.show()
if self.system_tray_icon.isVisible() and opts.start_in_tray:
@@ -582,10 +585,12 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
if idx == 1:
return self.memory_view
if idx == 2:
- return self.card_view
+ return self.card_a_view
+ if idx == 3:
+ return self.card_b_view
def booklists(self):
- return self.memory_view.model().db, self.card_view.model().db
+ return self.memory_view.model().db, self.card_a_view.model().db, self.card_b_view.model().db
@@ -647,12 +652,14 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
else:
self.device_job_exception(job)
return
- mainlist, cardlist = job.result
+ mainlist, cardalist, cardblist = job.result
self.memory_view.set_database(mainlist)
self.memory_view.set_editable(self.device_manager.device_class.CAN_SET_METADATA)
- self.card_view.set_database(cardlist)
- self.card_view.set_editable(self.device_manager.device_class.CAN_SET_METADATA)
- for view in (self.memory_view, self.card_view):
+ self.card_a_view.set_database(cardalist)
+ self.card_a_view.set_editable(self.device_manager.device_class.CAN_SET_METADATA)
+ self.card_b_view.set_database(cardblist)
+ self.card_b_view.set_editable(self.device_manager.device_class.CAN_SET_METADATA)
+ for view in (self.memory_view, self.card_a_view, self.card_b_view):
view.sortByColumn(3, Qt.DescendingOrder)
if not view.restore_column_widths():
view.resizeColumnsToContents()
@@ -793,8 +800,12 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
return
view.model().delete_books(rows)
else:
- view = self.memory_view if self.stack.currentIndex() == 1 \
- else self.card_view
+ if self.stack.currentIndex() == 1:
+ view = self.memory_view
+ elif self.stack.currentIndex() == 2:
+ view = self.card_a_view
+ else:
+ view = self.card_b_view
paths = view.model().paths(rows)
job = self.remove_paths(paths)
self.delete_memory[job] = (paths, view.model())
@@ -809,7 +820,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
'''
Called once deletion is done on the device
'''
- for view in (self.memory_view, self.card_view):
+ for view in (self.memory_view, self.card_a_view, self.card_b_view):
view.model().deletion_done(job, bool(job.exception))
if job.exception is not None:
self.device_job_exception(job)
@@ -1318,10 +1329,11 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
'''
Called when a location icon is clicked (e.g. Library)
'''
- page = 0 if location == 'library' else 1 if location == 'main' else 2
+ page = 0 if location == 'library' else 1 if location == 'main' else 2 if location == 'carda' else 3
self.stack.setCurrentIndex(page)
view = self.memory_view if page == 1 else \
- self.card_view if page == 2 else None
+ self.card_a_view if page == 2 else \
+ self.card_b_view if page == 3 else None
if view:
if view.resize_on_select:
view.resizeRowsToContents()
diff --git a/src/calibre/gui2/main.ui b/src/calibre/gui2/main.ui
index fbae01d3e6..24ba2a1c7a 100644
--- a/src/calibre/gui2/main.ui
+++ b/src/calibre/gui2/main.ui
@@ -288,7 +288,7 @@
- 0
+ 3
@@ -417,10 +417,48 @@
-
+
-
-
+
+
+
+ 10
+ 10
+
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ QAbstractItemView::DragDrop
+
+
+ true
+
+
+ QAbstractItemView::SelectRows
+
+
+ false
+
+
+ false
+
+
+
+
+
+
+
+ -
+
10
diff --git a/src/calibre/gui2/viewer/printing.py b/src/calibre/gui2/viewer/printing.py
index e948360338..8d9801e306 100644
--- a/src/calibre/gui2/viewer/printing.py
+++ b/src/calibre/gui2/viewer/printing.py
@@ -8,7 +8,7 @@ import os, sys, traceback, urlparse
from BeautifulSoup import BeautifulSoup, Tag
-from calibre.ebooks.epub.iterator import EbookIterator
+from calibre.ebooks.oeb.iterator import EbookIterator
from calibre.ptempfile import TemporaryDirectory
from PyQt4 import QtCore
diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py
index 535ec4251f..886320aedb 100644
--- a/src/calibre/gui2/widgets.py
+++ b/src/calibre/gui2/widgets.py
@@ -171,17 +171,20 @@ class LocationModel(QAbstractListModel):
QAbstractListModel.__init__(self, parent)
self.icons = [QVariant(QIcon(':/library')),
QVariant(QIcon(':/images/reader.svg')),
+ QVariant(QIcon(':/images/sd.svg')),
QVariant(QIcon(':/images/sd.svg'))]
self.text = [_('Library\n%d\nbooks'),
_('Reader\n%s\navailable'),
- _('Card\n%s\navailable')]
- self.free = [-1, -1]
+ _('Card A\n%s\navailable'),
+ _('Card B\n%s\navailable')]
+ self.free = [-1, -1, -1]
self.count = 0
self.highlight_row = 0
self.tooltips = [
_('Click to see the list of books available on your computer'),
_('Click to see the list of books in the main memory of your reader'),
- _('Click to see the list of books on the storage card in your reader')
+ _('Click to see the list of books on storage card A in your reader'),
+ _('Click to see the list of books on storage card B in your reader')
]
def rowCount(self, parent):
@@ -218,9 +221,14 @@ class LocationModel(QAbstractListModel):
def update_devices(self, cp=None, fs=[-1, -1, -1]):
self.free[0] = fs[0]
- self.free[1] = max(fs[1:])
- if cp == None:
+ self.free[1] = fs[1]
+ self.free[2] = fs[2]
+ if cp != None:
+ self.free[1] = fs[1] if fs[1] else -1
+ self.free[2] = fs[2] if fs[2] else -1
+ else:
self.free[1] = -1
+ self.free[2] = -1
self.reset()
def location_changed(self, row):
@@ -244,12 +252,12 @@ class LocationView(QListView):
def current_changed(self, current, previous):
if current.isValid():
i = current.row()
- location = 'library' if i == 0 else 'main' if i == 1 else 'card'
+ location = 'library' if i == 0 else 'main' if i == 1 else 'carda' if i == 2 else 'cardb'
self.emit(SIGNAL('location_selected(PyQt_PyObject)'), location)
self.model().location_changed(i)
def location_changed(self, row):
- if 0 <= row and row <= 2:
+ if 0 <= row and row <= 3:
self.model().location_changed(row)
class JobsView(TableView):