diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 15e8ffd170..6d06d623d4 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -687,7 +687,6 @@ from calibre.devices.misc import ( COBY, EX124G, WAYTEQ, WOXTER, POCKETBOOK626, SONYDPTS1) from calibre.devices.folder_device.driver import FOLDER_DEVICE_FOR_CONFIG from calibre.devices.kobo.driver import KOBO, KOBOTOUCH -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 from calibre.devices.mtp.driver import MTP_DEVICE @@ -752,7 +751,6 @@ plugins += [ PDNOVEL_KOBO, LUMIREAD, ALURATEK_COLOR, - BAMBOOK, TREKSTOR, EEEREADER, NEXTBOOK, diff --git a/src/calibre/customize/profiles.py b/src/calibre/customize/profiles.py index b32684f50d..cdd211e50a 100644 --- a/src/calibre/customize/profiles.py +++ b/src/calibre/customize/profiles.py @@ -776,21 +776,6 @@ class NookColorOutput(NookOutput): comic_screen_size = (594, 900) dpi = 169 -class BambookOutput(OutputProfile): - - author = 'Li Fanxi' - name = 'Sanda Bambook' - short_name = 'bambook' - description = _('This profile is intended for the Sanda Bambook.') - - # Screen size is for full screen display - screen_size = (580, 780) - # Comic size is for normal display - comic_screen_size = (540, 700) - dpi = 168.451 - fbase = 12 - fsizes = [10, 12, 14, 16] - class PocketBook900Output(OutputProfile): author = 'Chris Lockfort' @@ -821,7 +806,7 @@ output_profiles = [ iPad3Output, KoboReaderOutput, TabletOutput, SamsungGalaxy, SonyReaderLandscapeOutput, KindleDXOutput, IlliadOutput, NookHD, IRexDR1000Output, IRexDR800Output, JetBook5Output, NookOutput, - BambookOutput, NookColorOutput, PocketBook900Output, + NookColorOutput, PocketBook900Output, PocketBookPro912Output, GenericEink, GenericEinkLarge, GenericEinkHD, KindleFireOutput, KindlePaperWhiteOutput, KindleVoyageOutput, KindlePaperWhite3Output diff --git a/src/calibre/devices/bambook/__init__.py b/src/calibre/devices/bambook/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/calibre/devices/bambook/driver.py b/src/calibre/devices/bambook/driver.py deleted file mode 100644 index fecdd53ac4..0000000000 --- a/src/calibre/devices/bambook/driver.py +++ /dev/null @@ -1,544 +0,0 @@ -# -*- coding: utf-8 -*- - -__license__ = 'GPL v3' -__copyright__ = '2010, Li Fanxi ' -__docformat__ = 'restructuredtext en' - -''' -Device driver for Sanda's Bambook -''' - -import time, os, hashlib, shutil -from itertools import cycle -from calibre.devices.interface import DevicePlugin -from calibre.devices.usbms.deviceconfig import DeviceConfig -from calibre.devices.bambook.libbambookcore import Bambook, text_encoding, CONN_CONNECTED, is_bambook_lib_ready -from calibre.devices.usbms.books import Book, BookList -from calibre.ebooks.metadata.book.json_codec import JsonCodec -from calibre.ptempfile import TemporaryDirectory, TemporaryFile -from calibre.constants import __appname__, __version__ -from calibre.devices.errors import OpenFeedback - -class BAMBOOK(DeviceConfig, DevicePlugin): - name = 'Bambook Device Interface' - description = _('Communicate with the Sanda Bambook eBook reader.') - author = _('Li Fanxi') - supported_platforms = ['windows', 'linux', 'osx'] - log_packets = False - - booklist_class = BookList - book_class = Book - - ip = None - - FORMATS = [ "snb", "pdf" ] - USER_CAN_ADD_NEW_FORMATS = False - VENDOR_ID = 0x230b - PRODUCT_ID = 0x0001 - BCD = None - CAN_SET_METADATA = False - THUMBNAIL_HEIGHT = 155 - EXTRA_CUSTOMIZATION_MESSAGE = \ - _("Device IP Address (restart calibre after changing)") - - icon = I("devices/bambook.png") -# OPEN_FEEDBACK_MESSAGE = _( -# 'Connecting to Bambook device, please wait ...') - BACKLOADING_ERROR_MESSAGE = _( - 'Unable to add book to library directly from Bambook. ' - 'Please save the book to disk and add the file to library from disk.') - - METADATA_CACHE = '.calibre.bambook' - METADATA_FILE_GUID = 'calibremetadata.snb' - - bambook = None - is_connected = False - - def __init__(self, ip): - self.ip = ip - - def reset(self, key='-1', log_packets=False, report_progress=None, - detected_device=None) : - self.open(None, None) - - def open(self, connected_device, library_uuid): - # Make sure the Bambook library is ready - if not is_bambook_lib_ready(): - raise OpenFeedback(_("Unable to connect to Bambook, you need to install Bambook library first.")) - # Disconnect first if connected - self.eject() - # Connect - self.bambook = Bambook() - self.bambook.Connect(ip = self.ip, timeout = 10000) - if self.bambook.GetState() != CONN_CONNECTED: - self.bambook = None - raise OpenFeedback(_("Unable to connect to Bambook. \n" - "If you are trying to connect via Wi-Fi, " - "please make sure the IP address of Bambook has been correctly configured.")) - self.is_connected = True - return True - - def unmount_device(self): - self.eject() - - def eject(self): - if self.bambook: - self.bambook.Disconnect() - self.bambook = None - self.is_connected = False - - def post_yank_cleanup(self): - self.eject() - - def set_progress_reporter(self, report_progress): - ''' - :param report_progress: Function that is called with a % progress - (number between 0 and 100) for various tasks - If it is called with -1 that means that the - task does not have any progress information - - ''' - self.report_progress = report_progress - - def get_device_information(self, end_session=True): - """ - Ask device for device information. See L{DeviceInfoQuery}. - - :return: (device name, device version, software version on device, mime type) - - """ - if self.bambook: - deviceInfo = self.bambook.GetDeviceInfo() - return (_("Bambook"), "SD928", deviceInfo.firmwareVersion, "MimeType") - - def card_prefix(self, end_session=True): - ''' - 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) - ''' - return (None, None) - - def total_space(self, end_session=True): - """ - Get total space available on the mountpoints: - 1. Main memory - 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. - - """ - deviceInfo = self.bambook.GetDeviceInfo() - return (deviceInfo.deviceVolume * 1024, 0, 0) - - def free_space(self, end_session=True): - """ - Get free space available on the mountpoints: - 1. Main memory - 2. Card A - 3. Card B - - :return: A 3 element list with free space in bytes of (1, 2, 3). If a - particular device doesn't have any of these locations it should return -1. - - """ - deviceInfo = self.bambook.GetDeviceInfo() - return (deviceInfo.spareVolume * 1024, -1, -1) - - - def books(self, oncard=None, end_session=True): - """ - Return a list of ebooks on the device. - - :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. - - """ - # Bambook has no memroy card - if oncard: - return self.booklist_class(None, None, None) - - # Get metadata cache - prefix = '' - booklist = self.booklist_class(oncard, prefix, self.settings) - need_sync = self.parse_metadata_cache(booklist) - - # Get book list from device - devicebooks = self.bambook.GetBookList() - books = [] - for book in devicebooks: - if book.bookGuid == self.METADATA_FILE_GUID: - continue - b = self.book_class('', book.bookGuid) - b.title = book.bookName.decode(text_encoding) - b.authors = [ book.bookAuthor.decode(text_encoding) ] - b.size = 0 - b.datatime = time.gmtime() - b.lpath = book.bookGuid - b.thumbnail = None - b.tags = None - b.comments = book.bookAbstract.decode(text_encoding) - books.append(b) - - # make a dict cache of paths so the lookup in the loop below is faster. - bl_cache = {} - for idx, b in enumerate(booklist): - bl_cache[b.lpath] = idx - - def update_booklist(book, prefix): - changed = False - try: - idx = bl_cache.get(book.lpath, None) - if idx is not None: - bl_cache[book.lpath] = None - if self.update_metadata_item(book, booklist[idx]): - changed = True - else: - if booklist.add_book(book, - replace_metadata=False): - changed = True - except: # Probably a filename encoding error - import traceback - traceback.print_exc() - return changed - - # Check each book on device whether it has a correspondig item - # in metadata cache. If not, add it to cache. - for i, book in enumerate(books): - self.report_progress(i/float(len(books)), _('Getting list of books on device...')) - changed = update_booklist(book, prefix) - if changed: - need_sync = True - - # Remove books that are no longer in the Bambook. Cache contains - # indices into the booklist if book not in filesystem, None otherwise - # Do the operation in reverse order so indices remain valid - for idx in sorted(bl_cache.itervalues(), reverse=True): - if idx is not None: - need_sync = True - del booklist[idx] - - if need_sync: - self.sync_booklists((booklist, None, None)) - - self.report_progress(1.0, _('Getting list of books on device...')) - return booklist - - 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 :class:`FreeSpaceError` if there is not enough - free space on the device. The text of the FreeSpaceError must contain the - word "card" if ``on_card`` is not None otherwise it must contain the word "memory". - - :param files: A list of paths and/or file-like objects. If they are paths and - the paths point to temporary files, they may have an additional - attribute, original_file_path pointing to the originals. They may have - another optional attribute, deleted_after_upload which if True means - that the file pointed to by original_file_path will be deleted after - being uploaded to the device. - :param names: A list of file names that the books should have - once uploaded to the device. len(names) == len(files) - :param metadata: If not None, it is a list of :class:`Metadata` objects. - The idea is to use the metadata to determine where on the device to - put the book. len(metadata) == len(files). Apart from the regular - cover (path to cover), there may also be a thumbnail attribute, which should - be used in preference. The thumbnail attribute is of the form - (width, height, cover_data as jpeg). - - :return: A list of 3-element tuples. The list is meant to be passed - to :meth:`add_books_to_metadata`. - ''' - self.report_progress(0, _('Transferring books to device...')) - paths = [] - if self.bambook: - for (i, f) in enumerate(files): - self.report_progress((i+1) / float(len(files)), _('Transferring books to device...')) - if not hasattr(f, 'read'): - # Handle PDF File - if f[-3:].upper() == "PDF": - # Package the PDF file - with TemporaryDirectory() as tdir: - snbcdir = os.path.join(tdir, 'snbc') - snbfdir = os.path.join(tdir, 'snbf') - os.mkdir(snbcdir) - os.mkdir(snbfdir) - - tmpfile = open(os.path.join(snbfdir, 'book.snbf'), 'wb') - tmpfile.write(''' - - - - ZH-CN - - calibre - ''' + __appname__ + ' ' + __version__ + ''' - - - - - -''') - tmpfile.close() - tmpfile = open(os.path.join(snbfdir, 'toc.snbf'), 'wb') - tmpfile.write(''' - - 1 - - - - - -'''); - tmpfile.close() - pdf_name = os.path.join(snbcdir, "pdf1.pdf") - shutil.copyfile(f, pdf_name) - - with TemporaryFile('.snb') as snbfile: - if self.bambook.PackageSNB(snbfile, tdir) and self.bambook.VerifySNB(snbfile): - guid = self.bambook.SendFile(snbfile, self.get_guid(metadata[i].uuid)) - - elif f[-3:].upper() == 'SNB': - if self.bambook.VerifySNB(f): - guid = self.bambook.SendFile(f, self.get_guid(metadata[i].uuid)) - else: - print "book invalid" - if guid: - paths.append(guid) - else: - print "Send fail" - - ret = zip(paths, cycle([on_card])) - self.report_progress(1.0, _('Transferring books to device...')) - return ret - - def add_books_to_metadata(self, locations, metadata, booklists): - metadata = iter(metadata) - for i, location in enumerate(locations): - self.report_progress((i+1) / float(len(locations)), _('Adding books to device metadata listing...')) - info = metadata.next() - - # Extract the correct prefix from the pathname. To do this correctly, - # we must ensure that both the prefix and the path are normalized - # so that the comparison will work. Book's __init__ will fix up - # lpath, so we don't need to worry about that here. - - book = self.book_class('', location[0], other=info) - if book.size is None: - book.size = 0 - b = booklists[0].add_book(book, replace_metadata=True) - if b: - b._new_book = True - self.report_progress(1.0, _('Adding books to device metadata listing...')) - - def delete_books(self, paths, end_session=True): - ''' - Delete books at paths on device. - ''' - if self.bambook: - for i, path in enumerate(paths): - self.report_progress((i+1) / float(len(paths)), _('Removing books from device...')) - self.bambook.DeleteFile(path) - self.report_progress(1.0, _('Removing books from device...')) - - def remove_books_from_metadata(self, paths, booklists): - ''' - 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 - (:meth:`books(oncard=None)`, - :meth:`books(oncard='carda')`, - :meth`books(oncard='cardb')`). - - ''' - for i, path in enumerate(paths): - self.report_progress((i+1) / float(len(paths)), _('Removing books from device metadata listing...')) - for bl in booklists: - for book in bl: - if book.lpath == path: - bl.remove_book(book) - self.report_progress(1.0, _('Removing books from device metadata listing...')) - - def sync_booklists(self, booklists, end_session=True): - ''' - Update metadata on device. - - :param booklists: A tuple containing the result of calls to - (:meth:`books(oncard=None)`, - :meth:`books(oncard='carda')`, - :meth`books(oncard='cardb')`). - - ''' - if not self.bambook: - return - - json_codec = JsonCodec() - - # Create stub virtual book for sync info - with TemporaryDirectory() as tdir: - snbcdir = os.path.join(tdir, 'snbc') - snbfdir = os.path.join(tdir, 'snbf') - os.mkdir(snbcdir) - os.mkdir(snbfdir) - - f = open(os.path.join(snbfdir, 'book.snbf'), 'wb') - f.write(''' - - calibre同步信息 - calibre - ZH-CN - - calibre - ''' + __appname__ + ' ' + __version__ + ''' - - - - - -''') - f.close() - f = open(os.path.join(snbfdir, 'toc.snbf'), 'wb') - f.write(''' - - 0 - - - - -'''); - f.close() - cache_name = os.path.join(snbcdir, self.METADATA_CACHE) - with open(cache_name, 'wb') as f: - json_codec.encode_to_file(f, booklists[0]) - - with TemporaryFile('.snb') as f: - if self.bambook.PackageSNB(f, tdir): - if not self.bambook.SendFile(f, self.METADATA_FILE_GUID): - print "Upload failed" - else: - print "Package failed" - - # Clear the _new_book indication, as we are supposed to be done with - # adding books at this point - for blist in booklists: - if blist is not None: - for book in blist: - book._new_book = False - - self.report_progress(1.0, _('Sending metadata to device...')) - - def get_file(self, path, outfile, end_session=True): - ''' - Read the file at ``path`` on the device and write it to outfile. - - :param outfile: file object like ``sys.stdout`` or the result of an - :func:`open` call. - - ''' - if self.bambook: - with TemporaryDirectory() as tdir: - if self.bambook.GetFile(path, tdir): - filepath = os.path.join(tdir, path) - f = file(filepath, 'rb') - outfile.write(f.read()) - f.close() - else: - print "Unable to get file from Bambook:", path - - @classmethod - def config_widget(cls): - ''' - Should return a QWidget. The QWidget contains the settings for the device interface - ''' - from calibre.gui2.device_drivers.configwidget import ConfigWidget - cw = ConfigWidget(cls.settings(), cls.FORMATS, cls.SUPPORTS_SUB_DIRS, - cls.MUST_READ_METADATA, cls.SUPPORTS_USE_AUTHOR_SORT, - cls.EXTRA_CUSTOMIZATION_MESSAGE, cls) - # Turn off the Save template - cw.opt_save_template.setVisible(False) - cw.label.setVisible(False) - # Repurpose the metadata checkbox - cw.opt_read_metadata.setVisible(False) - # Repurpose the use_subdirs checkbox - cw.opt_use_subdirs.setVisible(False) - return cw - - - # @classmethod - # def save_settings(cls, settings_widget): - # ''' - # Should save settings to disk. Takes the widget created in - # :meth:`config_widget` and saves all settings to disk. - # ''' - # raise NotImplementedError() - - # @classmethod - # def settings(cls): - # ''' - # Should return an opts object. The opts object should have at least one attribute - # `format_map` which is an ordered list of formats for the device. - # ''' - # raise NotImplementedError() - - def parse_metadata_cache(self, bl): - need_sync = True - if not self.bambook: - return need_sync - - # Get the metadata virtual book from Bambook - with TemporaryDirectory() as tdir: - if self.bambook.GetFile(self.METADATA_FILE_GUID, tdir): - cache_name = os.path.join(tdir, self.METADATA_CACHE) - if self.bambook.ExtractSNBContent(os.path.join(tdir, self.METADATA_FILE_GUID), - 'snbc/' + self.METADATA_CACHE, - cache_name): - json_codec = JsonCodec() - if os.access(cache_name, os.R_OK): - try: - with open(cache_name, 'rb') as f: - json_codec.decode_from_file(f, bl, self.book_class, '') - need_sync = False - except: - import traceback - traceback.print_exc() - bl = [] - return need_sync - - @classmethod - def update_metadata_item(cls, book, blb): - # Currently, we do not have enough information - # from Bambook SDK to judge whether a book has - # been changed, we assume all books has been - # changed. - changed = True - # if book.bookName.decode(text_encoding) != blb.title: - # changed = True - # if book.bookAuthor.decode(text_encoding) != blb.authors[0]: - # changed = True - # if book.bookAbstract.decode(text_encoding) != blb.comments: - # changed = True - return changed - - @staticmethod - def get_guid(uuid): - guid = hashlib.md5(uuid).hexdigest()[0:15] + ".snb" - return guid - -class BAMBOOKWifi(BAMBOOK): - def is_usb_connected(self, devices_on_system, debug=False, - only_presence=False): - return self.is_connected, self diff --git a/src/calibre/devices/bambook/libbambookcore.py b/src/calibre/devices/bambook/libbambookcore.py deleted file mode 100644 index a1c6046df0..0000000000 --- a/src/calibre/devices/bambook/libbambookcore.py +++ /dev/null @@ -1,530 +0,0 @@ -# -*- coding: utf-8 -*- - -__license__ = 'GPL v3' -__copyright__ = '2010, Li Fanxi ' -__docformat__ = 'restructuredtext en' - -''' -Sanda library wrapper -''' - -import ctypes, hashlib, os, sys -from threading import Event, Lock -from calibre.constants import iswindows -from calibre import load_library - -try: - _lib_name = 'libBambookCore' - cdll = ctypes.cdll - if iswindows: - _lib_name = 'BambookCore' - if hasattr(sys, 'frozen') and iswindows: - lp = os.path.join(os.path.dirname(sys.executable), 'DLLs', 'BambookCore.dll') - lib_handle = cdll.LoadLibrary(lp) - elif hasattr(sys, 'frozen_path'): - lp = os.path.join(sys.frozen_path, 'lib', 'libBambookCore.so') - lib_handle = cdll.LoadLibrary(lp) - else: - lib_handle = load_library(_lib_name, cdll) -except: - lib_handle = None - -text_encoding = 'utf-8' -if iswindows: - text_encoding = 'mbcs' - -def is_bambook_lib_ready(): - return lib_handle != None - -# Constant -DEFAULT_BAMBOOK_IP = '192.168.250.2' -BAMBOOK_SDK_VERSION = 0x00090000 -BR_SUCC = 0 # 操作成功 -BR_FAIL = 1001 # 操作失败 -BR_NOT_IMPL = 1002 # 该功能还未实现 -BR_DISCONNECTED = 1003 # 与设备的连接已断开 -BR_PARAM_ERROR = 1004 # 调用函数传入的参数错误 -BR_TIMEOUT = 1005 # 操作或通讯超时 -BR_INVALID_HANDLE = 1006 # 传入的句柄无效 -BR_INVALID_FILE = 1007 # 传入的文件不存在或格式无效 -BR_INVALID_DIR = 1008 # 传入的目录不存在 -BR_BUSY = 1010 # 设备忙,另一个操作还未完成 -BR_EOF = 1011 # 文件或操作已结束 -BR_IO_ERROR = 1012 # 文件读写失败 -BR_FILE_NOT_INSIDE = 1013 # 指定的文件不在包里 - -# 当前连接状态 -CONN_CONNECTED = 0 # 已连接 -CONN_DISCONNECTED = 1 # 未连接或连接已断开 -CONN_CONNECTING = 2 # 正在连接 -CONN_WAIT_FOR_AUTH = 3 # 已连接,正在等待身份验证(暂未实现) - -#传输状态 -TRANS_STATUS_TRANS = 0 #正在传输 -TRANS_STATUS_DONE = 1 #传输完成 -TRANS_STATUS_ERR = 2 #传输出错 - -# Key Enums -BBKeyNum0 = 0 -BBKeyNum1 = 1 -BBKeyNum2 = 2 -BBKeyNum3 = 3 -BBKeyNum4 = 4 -BBKeyNum5 = 5 -BBKeyNum6 = 6 -BBKeyNum7 = 7 -BBKeyNum8 = 8 -BBKeyNum9 = 9 -BBKeyStar = 10 -BBKeyCross = 11 -BBKeyUp = 12 -BBKeyDown = 13 -BBKeyLeft = 14 -BBKeyRight = 15 -BBKeyPageUp = 16 -BBKeyPageDown = 17 -BBKeyOK = 18 -BBKeyESC = 19 -BBKeyBookshelf = 20 -BBKeyStore = 21 -BBKeyTTS = 22 -BBKeyMenu = 23 -BBKeyInteract =24 - -class DeviceInfo(ctypes.Structure): - _fields_ = [ ("cbSize", ctypes.c_int), - ("sn", ctypes.c_char * 20), - ("firmwareVersion", ctypes.c_char * 20), - ("deviceVolume", ctypes.c_int), - ("spareVolume", ctypes.c_int), - ] - def __init__(self): - self.cbSize = ctypes.sizeof(self) - -class PrivBookInfo(ctypes.Structure): - _fields_ = [ ("cbSize", ctypes.c_int), - ("bookGuid", ctypes.c_char * 20), - ("bookName", ctypes.c_char * 80), - ("bookAuthor", ctypes.c_char * 40), - ("bookAbstract", ctypes.c_char * 256), - ] - def Clone(self): - bookInfo = PrivBookInfo() - bookInfo.cbSize = self.cbSize - bookInfo.bookGuid = self.bookGuid - bookInfo.bookName = self.bookName - bookInfo.bookAuthor = self.bookAuthor - bookInfo.bookAbstract = self.bookAbstract - return bookInfo - - def __init__(self): - self.cbSize = ctypes.sizeof(self) - -# extern "C"_declspec(dllexport) BB_RESULT BambookConnect(const char* lpszIP, int timeOut, BB_HANDLE* hConn); -def BambookConnect(ip = DEFAULT_BAMBOOK_IP, timeout = 0): - if isinstance(ip, unicode): - ip = ip.encode('ascii') - handle = ctypes.c_void_p(0) - if lib_handle == None: - raise Exception(_('Bambook SDK has not been installed.')) - ret = lib_handle.BambookConnect(ip, timeout, ctypes.byref(handle)) - if ret == BR_SUCC: - return handle - else: - return None - -# extern "C" _declspec(dllexport) BB_RESULT BambookGetConnectStatus(BB_HANDLE hConn, int* status); -def BambookGetConnectStatus(handle): - status = ctypes.c_int(0) - ret = lib_handle.BambookGetConnectStatus(handle, ctypes.byref(status)) - if ret == BR_SUCC: - return status.value - else: - return None - -# extern "C" _declspec(dllexport) BB_RESULT BambookDisconnect(BB_HANDLE hConn); -def BambookDisconnect(handle): - ret = lib_handle.BambookDisconnect(handle) - if ret == BR_SUCC: - return True - else: - return False - -# extern "C" const char * BambookGetErrorString(BB_RESULT nCode) -def BambookGetErrorString(code): - func = lib_handle.BambookGetErrorString - func.restype = ctypes.c_char_p - return func(code) - - -# extern "C" BB_RESULT BambookGetSDKVersion(uint32_t * version); -def BambookGetSDKVersion(): - version = ctypes.c_int(0) - lib_handle.BambookGetSDKVersion(ctypes.byref(version)) - return version.value - -# extern "C" BB_RESULT BambookGetDeviceInfo(BB_HANDLE hConn, DeviceInfo* pInfo); -def BambookGetDeviceInfo(handle): - deviceInfo = DeviceInfo() - ret = lib_handle.BambookGetDeviceInfo(handle, ctypes.byref(deviceInfo)) - if ret == BR_SUCC: - return deviceInfo - else: - return None - - -# extern "C" BB_RESULT BambookKeyPress(BB_HANDLE hConn, BambookKey key); -def BambookKeyPress(handle, key): - ret = lib_handle.BambookKeyPress(handle, key) - if ret == BR_SUCC: - return True - else: - return False - -# extern "C" BB_RESULT BambookGetFirstPrivBookInfo(BB_HANDLE hConn, PrivBookInfo * pInfo); -def BambookGetFirstPrivBookInfo(handle, bookInfo): - bookInfo.contents.cbSize = ctypes.sizeof(bookInfo.contents) - ret = lib_handle.BambookGetFirstPrivBookInfo(handle, bookInfo) - if ret == BR_SUCC: - return True - else: - return False - -# extern "C" BB_RESULT BambookGetNextPrivBookInfo(BB_HANDLE hConn, PrivBookInfo * pInfo); -def BambookGetNextPrivBookInfo(handle, bookInfo): - bookInfo.contents.cbSize = ctypes.sizeof(bookInfo.contents) - ret = lib_handle.BambookGetNextPrivBookInfo(handle, bookInfo) - if ret == BR_SUCC: - return True - elif ret == BR_EOF: - return False - else: - return False - -# extern "C" BB_RESULT BambookDeletePrivBook(BB_HANDLE hConn, const char * lpszBookID); -def BambookDeletePrivBook(handle, guid): - if isinstance(guid, unicode): - guid = guid.encode('ascii') - ret = lib_handle.BambookDeletePrivBook(handle, guid) - if ret == BR_SUCC: - return True - else: - return False - -class JobQueue: - jobs = {} - maxID = 0 - lock = Lock() - def __init__(self): - self.maxID = 0 - - def NewJob(self): - self.lock.acquire() - self.maxID = self.maxID + 1 - maxid = self.maxID - self.lock.release() - event = Event() - self.jobs[maxid] = (event, TRANS_STATUS_TRANS) - return maxid - - def FinishJob(self, jobID, status): - self.jobs[jobID] = (self.jobs[jobID][0], status) - self.jobs[jobID][0].set() - - def WaitJob(self, jobID): - self.jobs[jobID][0].wait() - return (self.jobs[jobID][1] == TRANS_STATUS_DONE) - - def DeleteJob(self, jobID): - del self.jobs[jobID] - -job = JobQueue() - -def BambookTransferCallback(status, progress, userData): - if status == TRANS_STATUS_DONE and progress == 100: - job.FinishJob(userData, status) - elif status == TRANS_STATUS_ERR: - job.FinishJob(userData, status) - -TransCallback = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_int, ctypes.c_int) -bambookTransferCallback = TransCallback(BambookTransferCallback) - -# extern "C" BB_RESULT BambookAddPrivBook(BB_HANDLE hConn, const char * pszSnbFile, -# TransCallback pCallbackFunc, intptr_t userData); -def BambookAddPrivBook(handle, filename, callback, userData): - if isinstance(filename, unicode): - filename = filename.encode('ascii') - ret = lib_handle.BambookAddPrivBook(handle, filename, callback, userData) - if ret == BR_SUCC: - return True - else: - return False - -# extern "C" BB_RESULT BambookReplacePrivBook(BB_HANDLE hConn, const char * -# pszSnbFile, const char * lpszBookID, TransCallback pCallbackFunc, intptr_t userData); -def BambookReplacePrivBook(handle, filename, bookID, callback, userData): - if isinstance(filename, unicode): - filename = filename.encode('ascii') - if isinstance(bookID, unicode): - bookID = bookID.encode('ascii') - ret = lib_handle.BambookReplacePrivBook(handle, filename, bookID, callback, userData) - if ret == BR_SUCC: - return True - else: - return False - -# extern "C" BB_RESULT BambookFetchPrivBook(BB_HANDLE hConn, const char * -# lpszBookID, const char * lpszFilePath, TransCallback pCallbackFunc, intptr_t userData); -def BambookFetchPrivBook(handle, bookID, filename, callback, userData): - if isinstance(filename, unicode): - filename = filename.encode('ascii') - if isinstance(bookID, unicode): - bookID = bookID.encode('ascii') - ret = lib_handle.BambookFetchPrivBook(handle, bookID, filename, bambookTransferCallback, userData) - if ret == BR_SUCC: - return True - else: - return False - -# extern "C" BB_RESULT BambookVerifySnbFile(const char * snbName) -def BambookVerifySnbFile(filename): - if isinstance(filename, unicode): - filename = filename.encode('ascii') - if lib_handle.BambookVerifySnbFile(filename) == BR_SUCC: - return True - else: - return False - -# BB_RESULT BambookPackSnbFromDir ( const char * snbName,, const char * rootDir ); -def BambookPackSnbFromDir(snbFileName, rootDir): - if isinstance(snbFileName, unicode): - snbFileName = snbFileName.encode('ascii') - if isinstance(rootDir, unicode): - rootDir = rootDir.encode('ascii') - ret = lib_handle.BambookPackSnbFromDir(snbFileName, rootDir) - if ret == BR_SUCC: - return True - else: - return False - -# BB_RESULT BambookUnpackFileFromSnb ( const char * snbName,, const char * relativePath, const char * outfname ); -def BambookUnpackFileFromSnb(snbFileName, relPath, outFileName): - if isinstance(snbFileName, unicode): - snbFileName = snbFileName.encode('ascii') - if isinstance(relPath, unicode): - relPath = relPath.encode('ascii') - if isinstance(outFileName, unicode): - outFileName = outFileName.encode('ascii') - ret = lib_handle.BambookUnpackFileFromSnb(snbFileName, relPath, outFileName) - if ret == BR_SUCC: - return True - else: - return False - -class Bambook: - def __init__(self): - self.handle = None - - def Connect(self, ip = DEFAULT_BAMBOOK_IP, timeout = 10000): - if ip == None or ip == '': - ip = DEFAULT_BAMBOOK_IP - self.handle = BambookConnect(ip, timeout) - if self.handle and self.handle != 0: - return True - else: - return False - - def Disconnect(self): - if self.handle: - return BambookDisconnect(self.handle) - return False - - def GetState(self): - if self.handle: - return BambookGetConnectStatus(self.handle) - return CONN_DISCONNECTED - - def GetDeviceInfo(self): - if self.handle: - return BambookGetDeviceInfo(self.handle) - return None - - def SendFile(self, fileName, guid = None): - import uuid - if self.handle: - taskID = job.NewJob() - if guid: - if BambookReplacePrivBook(self.handle, fileName, guid, - bambookTransferCallback, taskID): - if(job.WaitJob(taskID)): - job.DeleteJob(taskID) - return guid - else: - job.DeleteJob(taskID) - return None - else: - job.DeleteJob(taskID) - return None - else: - guid = hashlib.md5(str(uuid.uuid4())).hexdigest()[0:15] + ".snb" - if BambookReplacePrivBook(self.handle, fileName, guid, - bambookTransferCallback, taskID): - if job.WaitJob(taskID): - job.DeleteJob(taskID) - return guid - else: - job.DeleteJob(taskID) - return None - else: - job.DeleteJob(taskID) - return None - return False - - def GetFile(self, guid, fileName): - if self.handle: - taskID = job.NewJob() - ret = BambookFetchPrivBook(self.handle, guid, fileName, bambookTransferCallback, taskID) - if ret: - ret = job.WaitJob(taskID) - job.DeleteJob(taskID) - return ret - else: - job.DeleteJob(taskID) - return False - return False - - def DeleteFile(self, guid): - if self.handle: - ret = BambookDeletePrivBook(self.handle, guid) - return ret - return False - - def GetBookList(self): - if self.handle: - books = [] - bookInfo = PrivBookInfo() - bi = ctypes.pointer(bookInfo) - - ret = BambookGetFirstPrivBookInfo(self.handle, bi) - while ret: - books.append(bi.contents.Clone()) - ret = BambookGetNextPrivBookInfo(self.handle, bi) - return books - - @staticmethod - def GetSDKVersion(): - return BambookGetSDKVersion() - - @staticmethod - def VerifySNB(fileName): - return BambookVerifySnbFile(fileName); - - @staticmethod - def ExtractSNBContent(fileName, relPath, path): - return BambookUnpackFileFromSnb(fileName, relPath, path) - - @staticmethod - def ExtractSNB(fileName, path): - ret = BambookUnpackFileFromSnb(fileName, 'snbf/book.snbf', path + '/snbf/book.snbf') - if not ret: - return False - ret = BambookUnpackFileFromSnb(fileName, 'snbf/toc.snbf', path + '/snbf/toc.snbf') - if not ret: - return False - - return True - - @staticmethod - def PackageSNB(fileName, path): - return BambookPackSnbFromDir(fileName, path) - -def passed(): - print "> Pass" - -def failed(): - print "> Failed" - -if __name__ == "__main__": - - print "Bambook SDK Unit Test" - bb = Bambook() - - print "Disconnect State" - if bb.GetState() == CONN_DISCONNECTED: - passed() - else: - failed() - - print "Get SDK Version" - if bb.GetSDKVersion() == BAMBOOK_SDK_VERSION: - passed() - else: - failed() - - print "Verify good SNB File" - if bb.VerifySNB(u'/tmp/f8268e6c1f4e78c.snb'): - passed() - else: - failed() - - print "Verify bad SNB File" - if not bb.VerifySNB('./libwrapper.py'): - passed() - else: - failed() - - print "Extract SNB File" - if bb.ExtractSNB('./test.snb', '/tmp/test'): - passed() - else: - failed() - - print "Packet SNB File" - if bb.PackageSNB('/tmp/tmp.snb', '/tmp/test') and bb.VerifySNB('/tmp/tmp.snb'): - passed() - else: - failed() - - print "Connect to Bambook" - if bb.Connect('192.168.250.2', 10000) and bb.GetState() == CONN_CONNECTED: - passed() - else: - failed() - - print "Get Bambook Info" - devInfo = bb.GetDeviceInfo() - if devInfo: -# print "Info Size: ", devInfo.cbSize -# print "SN: ", devInfo.sn -# print "Firmware: ", devInfo.firmwareVersion -# print "Capacity: ", devInfo.deviceVolume -# print "Free: ", devInfo.spareVolume - if devInfo.cbSize == 52 and devInfo.deviceVolume == 1714232: - passed() - else: - failed() - - print "Send file" - if bb.SendFile('/tmp/tmp.snb'): - passed() - else: - failed() - - print "Get book list" - books = bb.GetBookList() - if len(books) > 10: - passed() - else: - failed() - - print "Get book" - if bb.GetFile('f8268e6c1f4e78c.snb', '/tmp') and bb.VerifySNB('/tmp/f8268e6c1f4e78c.snb'): - passed() - else: - failed() - - print "Disconnect" - if bb.Disconnect(): - passed() - else: - failed() diff --git a/src/calibre/gui2/actions/device.py b/src/calibre/gui2/actions/device.py index 7baa8e62d9..f22d491928 100644 --- a/src/calibre/gui2/actions/device.py +++ b/src/calibre/gui2/actions/device.py @@ -13,8 +13,6 @@ from calibre.gui2.actions import InterfaceAction from calibre.utils.smtp import config as email_config from calibre.utils.config import tweaks from calibre.constants import iswindows, isosx, get_osx_version -from calibre.customize.ui import is_disabled -from calibre.devices.bambook.driver import BAMBOOK from calibre.gui2.dialogs.smartdevice import SmartdeviceDialog from calibre.gui2 import info_dialog, question_dialog from calibre.library.server import server_config as content_server_config @@ -23,7 +21,6 @@ class ShareConnMenu(QMenu): # {{{ connect_to_folder = pyqtSignal() connect_to_itunes = pyqtSignal() - connect_to_bambook = pyqtSignal() config_email = pyqtSignal() toggle_server = pyqtSignal() @@ -46,16 +43,6 @@ class ShareConnMenu(QMenu): # {{{ self.connect_to_itunes_action = mitem itunes_ok = iswindows or (isosx and get_osx_version() < (10, 9, 0)) mitem.setVisible(itunes_ok) - mitem = self.addAction(QIcon(I('devices/bambook.png')), _('Connect to Bambook')) - mitem.setEnabled(True) - mitem.triggered.connect(lambda x : self.connect_to_bambook.emit()) - self.connect_to_bambook_action = mitem - bambook_visible = False - if not is_disabled(BAMBOOK): - device_ip = BAMBOOK.settings().extra_customization - if device_ip: - bambook_visible = True - self.connect_to_bambook_action.setVisible(bambook_visible) self.addSeparator() self.toggle_server_action = \ @@ -76,7 +63,7 @@ class ShareConnMenu(QMenu): # {{{ r = parent.keyboard.register_shortcut prefix = 'Share/Connect Menu ' gr = ConnectShareAction.action_spec[0] - for attr in ('folder', 'bambook', 'itunes'): + for attr in ('folder', 'itunes'): if not (iswindows or isosx) and attr == 'itunes': continue ac = getattr(self, 'connect_to_%s_action'%attr) @@ -165,7 +152,6 @@ class ShareConnMenu(QMenu): # {{{ def set_state(self, device_connected, device): self.connect_to_folder_action.setEnabled(not device_connected) self.connect_to_itunes_action.setEnabled(not device_connected) - self.connect_to_bambook_action.setEnabled(not device_connected) # }}} @@ -206,7 +192,6 @@ class ConnectShareAction(InterfaceAction): self.qaction.setMenu(self.share_conn_menu) self.share_conn_menu.connect_to_folder.connect(self.gui.connect_to_folder) self.share_conn_menu.connect_to_itunes.connect(self.gui.connect_to_itunes) - self.share_conn_menu.connect_to_bambook.connect(self.gui.connect_to_bambook) def location_selected(self, loc): enabled = loc == 'library' diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index cf90ee1ff6..6de4622126 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -30,7 +30,6 @@ from calibre.devices.errors import (FreeSpaceError, WrongDestinationError, BlacklistedDevice) from calibre.devices.apple.driver import ITUNES_ASYNC from calibre.devices.folder_device.driver import FOLDER_DEVICE -from calibre.devices.bambook.driver import BAMBOOK, BAMBOOKWifi from calibre.constants import DEBUG from calibre.utils.config import tweaks, device_prefs from calibre.utils.img import scale_image @@ -941,10 +940,6 @@ class DeviceMixin(object): # {{{ if dir is not None: self.device_manager.mount_device(kls=FOLDER_DEVICE, kind='folder', path=dir) - def connect_to_bambook(self): - self.device_manager.mount_device(kls=BAMBOOKWifi, kind='bambook', - path=BAMBOOK.settings().extra_customization) - def connect_to_itunes(self): self.device_manager.mount_device(kls=ITUNES_ASYNC, kind='itunes', path=None) diff --git a/src/calibre/gui2/wizard/__init__.py b/src/calibre/gui2/wizard/__init__.py index 5635428c23..651e383325 100644 --- a/src/calibre/gui2/wizard/__init__.py +++ b/src/calibre/gui2/wizard/__init__.py @@ -353,13 +353,6 @@ class EZReaderPP(HanlinV5): manufacturer = 'Astak' id = 'ezreader_pp' -class Bambook(Device): - - name = 'Sanda Bambook' - output_format = 'SNB' - manufacturer = 'Sanda' - id = 'bambook' - output_profile = 'bambook' # }}} def get_devices():