From 1e19801b37b3f078630796ea6e02c3183fb8407f Mon Sep 17 00:00:00 2001 From: John Schember Date: Sun, 2 Aug 2009 13:37:19 -0400 Subject: [PATCH] Refactor and clean up of device drivers. --- src/calibre/devices/android/driver.py | 9 +-- src/calibre/devices/bebook/driver.py | 6 +- src/calibre/devices/blackberry/driver.py | 15 ++-- src/calibre/devices/cybookg3/driver.py | 98 +++++++---------------- src/calibre/devices/eb600/driver.py | 9 ++- src/calibre/devices/iliad/driver.py | 24 +----- src/calibre/devices/irexdr/driver.py | 27 +------ src/calibre/devices/jetbook/driver.py | 49 +++--------- src/calibre/devices/kindle/driver.py | 32 ++++---- src/calibre/devices/prs505/driver.py | 50 +++--------- src/calibre/devices/prs700/driver.py | 8 +- src/calibre/devices/usbms/books.py | 31 ++++--- src/calibre/devices/usbms/cli.py | 10 ++- src/calibre/devices/usbms/device.py | 59 +++++++++++--- src/calibre/devices/usbms/deviceconfig.py | 2 +- src/calibre/devices/usbms/driver.py | 61 +++----------- 16 files changed, 181 insertions(+), 309 deletions(-) diff --git a/src/calibre/devices/android/driver.py b/src/calibre/devices/android/driver.py index 98142b6b02..1c04e721ff 100644 --- a/src/calibre/devices/android/driver.py +++ b/src/calibre/devices/android/driver.py @@ -1,21 +1,18 @@ -#!/usr/bin/env python -# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai -from __future__ import with_statement +# -*- coding: utf-8 -*- __license__ = 'GPL v3' __copyright__ = '2009, Kovid Goyal ' __docformat__ = 'restructuredtext en' - from calibre.devices.usbms.driver import USBMS class ANDROID(USBMS): + name = 'Android driver' description = _('Communicate with Android phones.') author = 'Kovid Goyal' supported_platforms = ['windows', 'osx', 'linux'] - # Ordered list of supported formats FORMATS = ['epub'] @@ -34,5 +31,3 @@ class ANDROID(USBMS): MAIN_MEMORY_VOLUME_LABEL = 'Android Internal Memory' SUPPORTS_SUB_DIRS = True - - diff --git a/src/calibre/devices/bebook/driver.py b/src/calibre/devices/bebook/driver.py index e8bfece554..e490cabf21 100644 --- a/src/calibre/devices/bebook/driver.py +++ b/src/calibre/devices/bebook/driver.py @@ -1,5 +1,8 @@ +# -*- coding: utf-8 -*- + __license__ = 'GPL v3' __copyright__ = '2009, Tijmen Ruizendaal ' +__docformat__ = 'restructuredtext en' ''' Device driver for BeBook @@ -10,12 +13,12 @@ import re from calibre.devices.usbms.driver import USBMS class BEBOOK(USBMS): + name = 'BeBook driver' description = _('Communicate with the BeBook eBook reader.') author = 'Tijmen Ruizendaal' supported_platforms = ['windows', 'osx', 'linux'] - # Ordered list of supported formats FORMATS = ['mobi', 'epub', 'pdf', 'txt'] @@ -94,4 +97,3 @@ class BEBOOK_MINI(BEBOOK): MAIN_MEMORY_VOLUME_LABEL = 'BeBook Mini Internal Memory' STORAGE_CARD_VOLUME_LABEL = 'BeBook Mini Storage Card' - diff --git a/src/calibre/devices/blackberry/driver.py b/src/calibre/devices/blackberry/driver.py index da2328419a..24642cf980 100644 --- a/src/calibre/devices/blackberry/driver.py +++ b/src/calibre/devices/blackberry/driver.py @@ -1,9 +1,9 @@ -from __future__ import with_statement +# -*- coding: utf-8 -*- + __license__ = 'GPL 3' __copyright__ = '2009, Kovid Goyal ' __docformat__ = 'restructuredtext en' - from calibre.devices.usbms.driver import USBMS class BLACKBERRY(USBMS): @@ -15,18 +15,17 @@ class BLACKBERRY(USBMS): # Ordered list of supported formats FORMATS = ['mobi', 'prc'] - + VENDOR_ID = [0x0fca] PRODUCT_ID = [0x8004] BCD = [0x0200] - + VENDOR_NAME = 'RIM' WINDOWS_MAIN_MEM = 'BLACKBERRY_SD' - + #OSX_MAIN_MEM = 'Kindle Internal Storage Media' - + MAIN_MEMORY_VOLUME_LABEL = 'Blackberry Main Memory' - + EBOOK_DIR_MAIN = 'ebooks' SUPPORTS_SUB_DIRS = True - diff --git a/src/calibre/devices/cybookg3/driver.py b/src/calibre/devices/cybookg3/driver.py index 8c64637f57..359362b8cb 100644 --- a/src/calibre/devices/cybookg3/driver.py +++ b/src/calibre/devices/cybookg3/driver.py @@ -1,24 +1,26 @@ +# -*- coding: utf-8 -*- + __license__ = 'GPL v3' __copyright__ = '2009, John Schember ' +__docformat__ = 'restructuredtext en' + ''' Device driver for Bookeen's Cybook Gen 3 ''' import os -import shutil from itertools import cycle -from calibre.utils.filenames import ascii_filename as sanitize from calibre.devices.usbms.driver import USBMS import calibre.devices.cybookg3.t2b as t2b class CYBOOKG3(USBMS): - name = 'Cybook Gen 3/Opus Device Interface' - description = _('Communicate with the Cybook eBook reader.') + + name = 'Cybook Gen 3 Device Interface' + description = _('Communicate with the Cybook Gen 3 eBook reader.') author = _('John Schember') supported_platforms = ['windows', 'osx', 'linux'] - # Ordered list of supported formats # Be sure these have an entry in calibre.devices.mime FORMATS = ['mobi', 'prc', 'html', 'pdf', 'rtf', 'txt'] @@ -31,19 +33,21 @@ class CYBOOKG3(USBMS): WINDOWS_MAIN_MEM = 'CYBOOK_GEN3__-FD' WINDOWS_CARD_A_MEM = 'CYBOOK_GEN3__-SD' - OSX_MAIN_MEM = ['Bookeen Cybook Gen3 -FD Media', 'Bookeen Cybook Opus -FD Media'] + OSX_MAIN_MEM = 'Bookeen Cybook Gen3 -FD 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_A = "eBooks" + EBOOK_DIR_MAIN = 'eBooks' + EBOOK_DIR_CARD_A = 'eBooks' THUMBNAIL_HEIGHT = 144 + DELETE_EXTS = ['.mbp', '.dat', '_6090.t2b'] SUPPORTS_SUB_DIRS = True def upload_books(self, files, names, on_card=None, end_session=True, metadata=None): + path = self._sanity_check(on_card, files) paths = [] @@ -51,45 +55,16 @@ class CYBOOKG3(USBMS): metadata = iter(metadata) for i, infile in enumerate(files): - newpath = path - mdata = metadata.next() - - if 'tags' in mdata.keys(): - for tag in mdata['tags']: - if tag.startswith(_('News')): - newpath = os.path.join(newpath, 'news') - newpath = os.path.join(newpath, sanitize(mdata.get('title', ''))) - newpath = os.path.join(newpath, sanitize(mdata.get('timestamp', ''))) - elif tag.startswith('/'): - newpath += tag - newpath = os.path.normpath(newpath) - break - - if newpath == path: - newpath = os.path.join(newpath, sanitize(mdata.get('authors', _('Unknown')))) - newpath = os.path.join(newpath, sanitize(mdata.get('title', _('Unknown')))) - - if not os.path.exists(newpath): - os.makedirs(newpath) - - filepath = os.path.join(newpath, sanitize(names.next())) + mdata, fname = metadata.next(), names.next() + filepath = self.create_upload_path(path, mdata, fname) paths.append(filepath) - if hasattr(infile, 'read'): - infile.seek(0) - - dest = open(filepath, 'wb') - shutil.copyfileobj(infile, dest, 10*1024*1024) - - dest.flush() - dest.close() - else: - shutil.copy2(infile, filepath) + self.put_file(infile, filepath, replace_file=True) coverdata = None - if 'cover' in mdata.keys(): - if mdata['cover'] != None: - coverdata = mdata['cover'][2] + cover = mdata.get('cover', None) + if cover: + coverdata = cover[2] t2bfile = open('%s_6090.t2b' % (os.path.splitext(filepath)[0]), 'wb') t2b.write_t2b(t2bfile, coverdata) @@ -101,31 +76,13 @@ class CYBOOKG3(USBMS): return zip(paths, cycle([on_card])) - def delete_books(self, paths, end_session=True): - for i, path in enumerate(paths): - self.report_progress((i+1) / float(len(paths)), _('Removing books from device...')) - if os.path.exists(path): - os.unlink(path) - filepath, ext = os.path.splitext(path) +class CYBOOK_OPUS(USBMS): - # Delete the ebook auxiliary file - if os.path.exists(filepath + '.mbp'): - os.unlink(filepath + '.mbp') - if os.path.exists(filepath + '.dat'): - os.unlink(filepath + '.dat') - - # Delete the thumbnails file auto generated for the ebook - if os.path.exists(filepath + '_6090.t2b'): - os.unlink(filepath + '_6090.t2b') - - try: - os.removedirs(os.path.dirname(path)) - except: - pass - self.report_progress(1.0, _('Removing books from device...')) - -class CYBOOK_OPUS(CYBOOKG3): + name = 'Cybook Opus Device Interface' + description = _('Communicate with the Cybook Opus eBook reader.') + author = _('John Schember') + supported_platforms = ['windows', 'osx', 'linux'] FORMATS = ['epub', 'pdf', 'txt'] @@ -133,14 +90,13 @@ class CYBOOK_OPUS(CYBOOKG3): PRODUCT_ID = [0x0703] BCD = [0x110] + VENDOR_NAME = 'BOOKEEN' WINDOWS_MAIN_MEM = 'CYBOOK_OPUS__-FD' WINDOWS_CARD_A_MEM = 'CYBOOK_OPUS__-SD' OSX_MAIN_MEM = 'Bookeen Cybook Opus -FD Media' OSX_CARD_A_MEM = 'Bookeen Cybook Opus -SD Media' - def upload_books(self, *args, **kwargs): - USBMS.upload_books(self, *args, **kwargs) - - def delete_books(self, *args, **kwargs): - USBMS.delete_books(self, *args, **kwargs) + EBOOK_DIR_MAIN = 'eBooks' + EBOOK_DIR_CARD_A = 'eBooks' + SUPPORTS_SUB_DIRS = True diff --git a/src/calibre/devices/eb600/driver.py b/src/calibre/devices/eb600/driver.py index 70f527f79e..c9d0b0b22f 100644 --- a/src/calibre/devices/eb600/driver.py +++ b/src/calibre/devices/eb600/driver.py @@ -1,5 +1,9 @@ +# -*- coding: utf-8 -*- + __license__ = 'GPL v3' __copyright__ = '2009, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + ''' Device driver for the Netronix EB600 @@ -14,13 +18,15 @@ Windows PNP strings: from calibre.devices.usbms.driver import USBMS class EB600(USBMS): + name = 'Netronix EB600 Device Interface' description = _('Communicate with the EB600 eBook reader.') author = _('Kovid Goyal') supported_platforms = ['windows', 'osx', 'linux'] # Ordered list of supported formats - FORMATS = ['epub', 'mobi', 'prc', 'chm', 'djvu', 'html', 'rtf', 'txt', 'pdf'] + FORMATS = ['epub', 'mobi', 'prc', 'chm', 'djvu', 'html', 'rtf', 'txt', + 'pdf'] DRM_FORMATS = ['prc', 'mobi', 'html', 'pdf', 'txt'] VENDOR_ID = [0x1f85] @@ -59,4 +65,3 @@ class COOL_ER(EB600): WINDOWS_MAIN_MEM = 'EREADER' EBOOK_DIR_MAIN = 'my docs' - diff --git a/src/calibre/devices/iliad/driver.py b/src/calibre/devices/iliad/driver.py index 403598d506..1b007fc30b 100644 --- a/src/calibre/devices/iliad/driver.py +++ b/src/calibre/devices/iliad/driver.py @@ -8,17 +8,15 @@ __docformat__ = 'restructuredtext en' Device driver for IRex Iliad ''' -import os - from calibre.devices.usbms.driver import USBMS class ILIAD(USBMS): + name = 'IRex Iliad Device Interface' description = _('Communicate with the IRex Iliad eBook reader.') author = _('John Schember') supported_platforms = ['windows', 'linux'] - # Ordered list of supported formats # Be sure these have an entry in calibre.devices.mime FORMATS = ['mobi', 'prc', 'html', 'pdf', 'txt'] @@ -35,23 +33,5 @@ class ILIAD(USBMS): MAIN_MEMORY_VOLUME_LABEL = 'IRex Iliad Main Memory' EBOOK_DIR_MAIN = 'books' + DELETE_EXTS = ['.mbp'] SUPPORTS_SUB_DIRS = True - - def delete_books(self, paths, end_session=True): - for i, path in enumerate(paths): - self.report_progress((i+1) / float(len(paths)), _('Removing books from device...')) - if os.path.exists(path): - os.unlink(path) - - filepath, ext = os.path.splitext(path) - - # Delete the ebook auxiliary file - if os.path.exists(filepath + '.mbp'): - os.unlink(filepath + '.mbp') - - try: - os.removedirs(os.path.dirname(path)) - except: - pass - - self.report_progress(1.0, _('Removing books from device...')) diff --git a/src/calibre/devices/irexdr/driver.py b/src/calibre/devices/irexdr/driver.py index 51826a411e..dc5416ea22 100644 --- a/src/calibre/devices/irexdr/driver.py +++ b/src/calibre/devices/irexdr/driver.py @@ -8,17 +8,16 @@ __docformat__ = 'restructuredtext en' Device driver for IRex Digiatal Reader ''' -import os - from calibre.devices.usbms.driver import USBMS class IREXDR1000(USBMS): + name = 'IRex Digital Reader 1000 Device Interface' - description = _('Communicate with the IRex Digital Reader 1000 eBook reader.') + description = _('Communicate with the IRex Digital Reader 1000 eBook ' \ + 'reader.') author = _('John Schember') supported_platforms = ['windows', 'osx', 'linux'] - # Ordered list of supported formats # Be sure these have an entry in calibre.devices.mime FORMATS = ['epub', 'mobi', 'prc', 'html', 'pdf', 'txt'] @@ -35,23 +34,5 @@ class IREXDR1000(USBMS): MAIN_MEMORY_VOLUME_LABEL = 'IRex Digital Reader 1000 Main Memory' EBOOK_DIR_MAIN = 'ebooks' + DELETE_EXTS = ['.mbp'] SUPPORTS_SUB_DIRS = True - - def delete_books(self, paths, end_session=True): - for i, path in enumerate(paths): - self.report_progress((i+1) / float(len(paths)), _('Removing books from device...')) - if os.path.exists(path): - os.unlink(path) - - filepath, ext = os.path.splitext(path) - - # Delete the ebook auxiliary file - if os.path.exists(filepath + '.mbp'): - os.unlink(filepath + '.mbp') - - try: - os.removedirs(os.path.dirname(path)) - except: - pass - - self.report_progress(1.0, _('Removing books from device...')) diff --git a/src/calibre/devices/jetbook/driver.py b/src/calibre/devices/jetbook/driver.py index c6668364a7..8fcbe306a2 100644 --- a/src/calibre/devices/jetbook/driver.py +++ b/src/calibre/devices/jetbook/driver.py @@ -1,10 +1,16 @@ +# -*- coding: utf-8 -*- + __license__ = 'GPL v3' __copyright__ = '2009, James Ralston ' +__docformat__ = 'restructuredtext en' + ''' Device driver for Ectaco Jetbook firmware >= JL04_v030e ''' -import os, re, sys, shutil +import os +import re +import sys from itertools import cycle from calibre.devices.usbms.driver import USBMS @@ -54,46 +60,18 @@ class JETBOOK(USBMS): metadata = iter(metadata) for i, infile in enumerate(files): - newpath = path - - mdata = metadata.next() - - if 'tags' in mdata.keys(): - for tag in mdata['tags']: - if tag.startswith(_('News')): - newpath = os.path.join(newpath, 'news') - newpath = os.path.join(newpath, mdata.get('title', '')) - newpath = os.path.join(newpath, mdata.get('timestamp', '')) - break - elif tag.startswith('/'): - newpath += tag - newpath = os.path.normpath(newpath) - break + mdata, fname = metadata.next(), names.next() + path = os.path.dirname(self.create_upload_path(path, mdata, fname)) author = sanitize(mdata.get('authors','Unknown')).replace(' ', '_') title = sanitize(mdata.get('title', 'Unknown')).replace(' ', '_') - fileext = os.path.splitext(os.path.basename(names.next()))[1] + fileext = os.path.splitext(os.path.basename(fname))[1] fname = '%s#%s%s' % (author, title, fileext) - if newpath == path: - newpath = os.path.join(newpath, author, title) - - if not os.path.exists(newpath): - os.makedirs(newpath) - - filepath = os.path.join(newpath, fname) + filepath = os.path.join(path, fname) paths.append(filepath) - if hasattr(infile, 'read'): - infile.seek(0) - - dest = open(filepath, 'wb') - shutil.copyfileobj(infile, dest, 10*1024*1024) - - dest.flush() - dest.close() - else: - shutil.copy2(infile, filepath) + self.put_file(infile, filepath, replace_file=True) self.report_progress((i+1) / float(len(files)), _('Transferring books to device...')) @@ -132,6 +110,3 @@ class JETBOOK(USBMS): drives['carda'] = main return drives - - - diff --git a/src/calibre/devices/kindle/driver.py b/src/calibre/devices/kindle/driver.py index 1052ab87a0..f947d33773 100644 --- a/src/calibre/devices/kindle/driver.py +++ b/src/calibre/devices/kindle/driver.py @@ -1,14 +1,21 @@ +# -*- coding: utf-8 -*- + __license__ = 'GPL v3' __copyright__ = '2009, John Schember ' +__docformat__ = 'restructuredtext en' + ''' Device driver for Amazon's Kindle ''' -import os, re, sys +import os +import re +import sys from calibre.devices.usbms.driver import USBMS class KINDLE(USBMS): + name = 'Kindle Device Interface' description = _('Communicate with the Kindle eBook reader.') author = _('John Schember') @@ -31,26 +38,14 @@ class KINDLE(USBMS): MAIN_MEMORY_VOLUME_LABEL = 'Kindle Main Memory' STORAGE_CARD_VOLUME_LABEL = 'Kindle Storage Card' - EBOOK_DIR_MAIN = "documents" - EBOOK_DIR_CARD_A = "documents" + EBOOK_DIR_MAIN = 'documents' + EBOOK_DIR_CARD_A = 'documents' + DELETE_EXTS = ['.mbp'] SUPPORTS_SUB_DIRS = True WIRELESS_FILE_NAME_PATTERN = re.compile( r'(?P[^-]+)-asin_(?P<asin>[a-zA-Z\d]{10,})-type_(?P<type>\w{4})-v_(?P<index>\d+).*') - def delete_books(self, paths, end_session=True): - for i, path in enumerate(paths): - self.report_progress((i+1) / float(len(paths)), _('Removing books from device...')) - if os.path.exists(path): - os.unlink(path) - - filepath = os.path.splitext(path)[0] - - # Delete the ebook auxiliary file - if os.path.exists(filepath + '.mbp'): - os.unlink(filepath + '.mbp') - self.report_progress(1.0, _('Removing books from device...')) - @classmethod def metadata_from_path(cls, path): mi = cls.metadata_from_formats([path]) @@ -65,6 +60,7 @@ class KINDLE(USBMS): class KINDLE2(KINDLE): + name = 'Kindle 2 Device Interface' description = _('Communicate with the Kindle 2 eBook reader.') author = _('John Schember') @@ -73,7 +69,9 @@ class KINDLE2(KINDLE): PRODUCT_ID = [0x0002] BCD = [0x0100] + class KINDLE_DX(KINDLE): + name = 'Kindle DX Device Interface' description = _('Communicate with the Kindle 2 eBook reader.') author = _('John Schember') @@ -83,5 +81,3 @@ class KINDLE_DX(KINDLE): PRODUCT_ID = [0x0003] BCD = [0x0100] - - diff --git a/src/calibre/devices/prs505/driver.py b/src/calibre/devices/prs505/driver.py index 8107d7cc97..a2a1730105 100644 --- a/src/calibre/devices/prs505/driver.py +++ b/src/calibre/devices/prs505/driver.py @@ -1,15 +1,21 @@ +# -*- coding: utf-8 -*- + __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net> ' \ '2009, John Schember <john at nachtimwald.com>' +__docformat__ = 'restructuredtext en' + ''' Device driver for the SONY PRS-505 ''' -import os, re, time + +import os +import re +import time from itertools import cycle 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 __appname__ @@ -80,7 +86,6 @@ class PRS505(CLI, Device): self.report_progress(1.0, _('Get device information...')) return (self.__class__.__name__, '', '', '') - def books(self, oncard=None, end_session=True): if oncard == 'carda' and not self._card_a_prefix: self.report_progress(1.0, _('Getting list of books on device...')) @@ -105,48 +110,13 @@ class PRS505(CLI, Device): def upload_books(self, files, names, on_card=None, end_session=True, metadata=None): - 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'): - obj.seek(0, 2) - size = obj.tell() - obj.seek(0) - return size - return os.path.getsize(obj) - - sizes = [get_size(f) for f in files] - size = sum(sizes) - - 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")) + path = self._sanity_check(on_card, files) paths, ctimes = [], [] - names = iter(names) metadata = iter(metadata) for i, infile in enumerate(files): - close = False - if not hasattr(infile, 'read'): - infile, close = open(infile, 'rb'), True - infile.seek(0) - mdata, fname = metadata.next(), names.next() filepath = self.create_upload_path(path, mdata, fname) @@ -154,8 +124,6 @@ class PRS505(CLI, Device): self.put_file(infile, paths[-1], replace_file=True) - if close: - infile.close() ctimes.append(os.path.getctime(paths[-1])) self.report_progress((i+1) / float(len(files)), _('Transferring books to device...')) diff --git a/src/calibre/devices/prs700/driver.py b/src/calibre/devices/prs700/driver.py index a79902fe10..1354685431 100644 --- a/src/calibre/devices/prs700/driver.py +++ b/src/calibre/devices/prs700/driver.py @@ -1,5 +1,8 @@ +# -*- coding: utf-8 -*- + __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>' +__docformat__ = 'restructuredtext en' ''' Device driver for the SONY PRS-700 @@ -13,9 +16,9 @@ class PRS700(PRS505): description = _('Communicate with the Sony PRS-700 eBook reader.') author = _('Kovid Goyal and John Schember') supported_platforms = ['windows', 'osx', 'linux'] - + BCD = [0x31a] - + WINDOWS_MAIN_MEM = 'PRS-700' WINDOWS_CARD_A_MEM = 'PRS-700/UC:MS' WINDOWS_CARD_B_MEM = 'PRS-700/UC:SD' @@ -23,4 +26,3 @@ class PRS700(PRS505): 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/books.py b/src/calibre/devices/usbms/books.py index 2875c04b88..fe69bd1579 100644 --- a/src/calibre/devices/usbms/books.py +++ b/src/calibre/devices/usbms/books.py @@ -1,13 +1,17 @@ -__license__ = 'GPL v3' -__copyright__ = '2009, John Schember <john at nachtimwald.com>' -''' -''' +# -*- coding: utf-8 -*- -import os, fnmatch, re, time +__license__ = 'GPL 3' +__copyright__ = '2009, John Schember <john@nachtimwald.com>' +__docformat__ = 'restructuredtext en' + +import os +import re +import time from calibre.devices.interface import BookList as _BookList class Book(object): + def __init__(self, path, title, authors, mime): self.title = title self.authors = authors @@ -17,30 +21,33 @@ class Book(object): self.path = path self.thumbnail = None self.tags = [] - + def __eq__(self, other): return self.path == other.path - + @dynamic_property def title_sorter(self): doc = '''String to sort the title. If absent, title is returned''' def fget(self): return re.sub('^\s*A\s+|^\s*The\s+|^\s*An\s+', '', self.title).rstrip() return property(doc=doc, fget=fget) - + @dynamic_property def thumbnail(self): return None - + def __str__(self): - """ Return a utf-8 encoded string with title author and path information """ + ''' + Return a utf-8 encoded string with title author and path information + ''' return self.title.encode('utf-8') + " by " + \ self.authors.encode('utf-8') + " at " + self.path.encode('utf-8') + class BookList(_BookList): + def supports_tags(self): return False - + def set_tags(self, book, tags): pass - diff --git a/src/calibre/devices/usbms/cli.py b/src/calibre/devices/usbms/cli.py index 9438db5952..e8b98c8dae 100644 --- a/src/calibre/devices/usbms/cli.py +++ b/src/calibre/devices/usbms/cli.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- -from __future__ import with_statement __license__ = 'GPL 3' __copyright__ = '2009, John Schember <john@nachtimwald.com>' __docformat__ = 'restructuredtext en' -import os, shutil +import os +import shutil from calibre.devices.errors import PathError @@ -33,6 +33,10 @@ class CLI(object): def put_file(self, infile, path, replace_file=False, end_session=True): path = self.munge_path(path) + close = False + if not hasattr(infile, 'read'): + infile, close = open(infile, 'rb'), True + infile.seek(0) if os.path.isdir(path): path = os.path.join(path, infile.name) if not replace_file and os.path.exists(path): @@ -44,6 +48,8 @@ class CLI(object): shutil.copyfileobj(infile, dest, 10*1024*1024) dest.flush() dest.close() + if close: + infile.close() def munge_path(self, path): if path.startswith('/') and not (path.startswith(self._main_prefix) or \ diff --git a/src/calibre/devices/usbms/device.py b/src/calibre/devices/usbms/device.py index 60903766fd..7c6591114b 100644 --- a/src/calibre/devices/usbms/device.py +++ b/src/calibre/devices/usbms/device.py @@ -1,13 +1,23 @@ +# -*- coding: utf-8 -*- + __license__ = 'GPL v3' -__copyright__ = '''2009, John Schember <john at nachtimwald.com> - and Kovid Goyal <kovid@kovidgoyal.net>''' +__copyright__ = '2009, John Schember <john at nachtimwald.com> ' \ + '2009, Kovid Goyal <kovid@kovidgoyal.net>' +__docformat__ = 'restructuredtext en' + ''' Generic device driver. This is not a complete stand alone driver. It is intended to be subclassed with the relevant parts implemented for a particular device. This class handles device detection. ''' -import os, subprocess, time, re, sys, glob, shutil +import os +import subprocess +import time +import re +import sys +import glob +import shutil from itertools import repeat from math import ceil @@ -18,6 +28,7 @@ from calibre import iswindows, islinux, isosx, __appname__ from calibre.utils.filenames import ascii_filename as sanitize class Device(DeviceConfig, DevicePlugin): + ''' This class provides logic common to all drivers for devices that export themselves as USB Mass Storage devices. If you are writing such a driver, inherit from this @@ -240,7 +251,6 @@ class Device(DeviceConfig, DevicePlugin): return True return False - time.sleep(6) drives = {} wmi = __import__('wmi', globals(), locals(), [], -1) @@ -294,7 +304,6 @@ class Device(DeviceConfig, DevicePlugin): return True return False - def get_osx_mountpoints(self, raw=None): raw = self.run_ioreg(raw) lines = raw.splitlines() @@ -458,7 +467,6 @@ class Device(DeviceConfig, DevicePlugin): return node return nodes[-1][0] - def open_linux(self): def mount(node, type): @@ -497,7 +505,6 @@ class Device(DeviceConfig, DevicePlugin): return None, ret return self.node_mountpoint(node)+'/', 0 - main, carda, cardb = self.find_device_nodes() if main is None: raise DeviceError(_('Unable to detect the %s disk drive.') @@ -600,7 +607,6 @@ class Device(DeviceConfig, DevicePlugin): except: pass - def eject(self): if islinux: try: @@ -619,6 +625,40 @@ class Device(DeviceConfig, DevicePlugin): pass self._main_prefix = self._card_a_prefix = self._card_b_prefix = None + def _sanity_check(self, on_card, files): + 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(_('Selected slot: %s is not supported.') % on_card) + + if on_card == 'carda': + path = os.path.join(self._card_a_prefix, self.EBOOK_DIR_CARD_A) + elif on_card == 'cardb': + path = os.path.join(self._card_b_prefix, self.EBOOK_DIR_CARD_B) + else: + path = os.path.join(self._main_prefix, self.EBOOK_DIR_MAIN) + + def get_size(obj): + if hasattr(obj, 'seek'): + obj.seek(0, os.SEEK_END) + size = obj.tell() + obj.seek(0) + return size + return os.path.getsize(obj) + + sizes = [get_size(f) for f in files] + size = sum(sizes) + + 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")) + return path + def create_upload_path(self, path, mdata, fname): resizable = [] newpath = path @@ -681,10 +721,7 @@ class Device(DeviceConfig, DevicePlugin): filepath = filepath.replace(os.sep+os.sep, os.sep) newpath = os.path.dirname(filepath) - if not os.path.exists(newpath): os.makedirs(newpath) return filepath - - diff --git a/src/calibre/devices/usbms/deviceconfig.py b/src/calibre/devices/usbms/deviceconfig.py index 344b8fcc46..64cfccce68 100644 --- a/src/calibre/devices/usbms/deviceconfig.py +++ b/src/calibre/devices/usbms/deviceconfig.py @@ -41,7 +41,7 @@ class DeviceConfig(object): @classmethod def settings(cls): return cls._config().parse() - + @classmethod def customization_help(cls, gui=False): return cls.HELP_MESSAGE diff --git a/src/calibre/devices/usbms/driver.py b/src/calibre/devices/usbms/driver.py index 486bb46472..34d2c137ce 100644 --- a/src/calibre/devices/usbms/driver.py +++ b/src/calibre/devices/usbms/driver.py @@ -1,5 +1,9 @@ +# -*- coding: utf-8 -*- + __license__ = 'GPL v3' __copyright__ = '2009, John Schember <john at nachtimwald.com>' +__docformat__ = 'restructuredtext en' + ''' Generic USB Mass storage device driver. This is not a complete stand alone driver. It is intended to be subclassed with the relevant parts implemented @@ -9,14 +13,12 @@ for a particular device. import os import fnmatch import re -import shutil from itertools import cycle 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 DeviceError, FreeSpaceError from calibre.devices.mime import mime_type_ext # CLI must come before Device as it implments the CLI functions that @@ -32,6 +34,7 @@ class USBMS(CLI, Device): EBOOK_DIR_MAIN = '' EBOOK_DIR_CARD_A = '' EBOOK_DIR_CARD_B = '' + DELETE_EXTS = [] CAN_SET_METADATA = False def reset(self, key='-1', log_packets=False, report_progress=None): @@ -80,40 +83,6 @@ class USBMS(CLI, Device): return bl - def _sanity_check(self, on_card, files): - 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(_('Selected slot: %s is not supported.') % on_card) - - if on_card == 'carda': - path = os.path.join(self._card_a_prefix, self.EBOOK_DIR_CARD_A) - elif on_card == 'cardb': - path = os.path.join(self._card_b_prefix, self.EBOOK_DIR_CARD_B) - else: - path = os.path.join(self._main_prefix, self.EBOOK_DIR_MAIN) - - def get_size(obj): - if hasattr(obj, 'seek'): - obj.seek(0, os.SEEK_END) - size = obj.tell() - obj.seek(0) - return size - return os.path.getsize(obj) - - sizes = [get_size(f) for f in files] - size = sum(sizes) - - 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")) - return path - def upload_books(self, files, names, on_card=None, end_session=True, metadata=None): @@ -129,16 +98,7 @@ class USBMS(CLI, Device): paths.append(filepath) - if hasattr(infile, 'read'): - infile.seek(0) - - dest = open(filepath, 'wb') - shutil.copyfileobj(infile, dest, 10*1024*1024) - - dest.flush() - dest.close() - else: - shutil.copy2(infile, filepath) + self.put_file(infile, filepath, replace_file=True) self.report_progress((i+1) / float(len(files)), _('Transferring books to device...')) @@ -146,7 +106,6 @@ class USBMS(CLI, Device): return zip(paths, cycle([on_card])) - def add_books_to_metadata(self, locations, metadata, booklists): for i, location in enumerate(locations): self.report_progress((i+1) / float(len(locations)), _('Adding books to device metadata listing...')) @@ -159,13 +118,18 @@ class USBMS(CLI, Device): booklists[blist].append(book) self.report_progress(1.0, _('Adding books to device metadata listing...')) - def delete_books(self, paths, end_session=True): for i, path in enumerate(paths): self.report_progress((i+1) / float(len(paths)), _('Removing books from device...')) if os.path.exists(path): # Delete the ebook os.unlink(path) + + filepath = os.path.splitext(path)[0] + for ext in self.DELETE_EXTS: + if os.path.exists(filepath + ext): + os.unlink(filepath + ext) + if self.SUPPORTS_SUB_DIRS: try: os.removedirs(os.path.dirname(path)) @@ -199,7 +163,6 @@ class USBMS(CLI, Device): with quick_metadata: return metadata_from_formats(fmts) - @classmethod def book_from_path(cls, path): from calibre.ebooks.metadata.meta import path_to_ext