home *** CD-ROM | disk | FTP | other *** search
- # Source Generated with Decompyle++
- # File: in.pyc (Python 2.6)
-
- __license__ = 'GPL v3'
- __copyright__ = '2009, John Schember <john at nachtimwald.com>'
- __docformat__ = 'restructuredtext en'
- import datetime
- import os
- import re
- import sys
- import json
- import hashlib
- from cStringIO import StringIO
- from struct import unpack
- from calibre.devices.usbms.driver import USBMS
-
- class KINDLE(USBMS):
- name = 'Kindle Device Interface'
- gui_name = 'Amazon Kindle'
- icon = I('devices/kindle.jpg')
- description = _('Communicate with the Kindle eBook reader.')
- author = 'John Schember'
- supported_platforms = [
- 'windows',
- 'osx',
- 'linux']
- FORMATS = [
- 'azw',
- 'mobi',
- 'prc',
- 'azw1',
- 'tpz',
- 'txt']
- VENDOR_ID = [
- 6473]
- PRODUCT_ID = [
- 1]
- BCD = [
- 921]
- VENDOR_NAME = 'KINDLE'
- WINDOWS_MAIN_MEM = 'INTERNAL_STORAGE'
- WINDOWS_CARD_A_MEM = 'CARD_STORAGE'
- OSX_MAIN_MEM = 'Kindle Internal 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_A = 'documents'
- DELETE_EXTS = [
- '.mbp',
- '.tan',
- '.pdr']
- SUPPORTS_SUB_DIRS = True
- SUPPORTS_ANNOTATIONS = True
- WIRELESS_FILE_NAME_PATTERN = re.compile('(?P<title>[^-]+)-asin_(?P<asin>[a-zA-Z\\d]{10,})-type_(?P<type>\\w{4})-v_(?P<index>\\d+).*')
-
- def metadata_from_path(cls, path):
- mi = cls.metadata_from_formats([
- path])
- if (mi.title == _('Unknown') or '-asin' in mi.title) and '-type' in mi.title:
- match = cls.WIRELESS_FILE_NAME_PATTERN.match(os.path.basename(path))
- if match is not None:
- mi.title = match.group('title')
- if not isinstance(mi.title, unicode):
- mi.title = mi.title.decode(sys.getfilesystemencoding(), 'replace')
-
-
-
- return mi
-
- metadata_from_path = classmethod(metadata_from_path)
-
- def get_annotations(self, path_map):
- MBP_FORMATS = [
- u'azw',
- u'mobi',
- u'prc',
- u'txt']
- mbp_formats = set(MBP_FORMATS)
- PDR_FORMATS = [
- u'pdf']
- pdr_formats = set(PDR_FORMATS)
- TAN_FORMATS = [
- u'tpz',
- u'azw1']
- tan_formats = set(TAN_FORMATS)
-
- def get_storage():
- storage = []
- if self._main_prefix:
- storage.append(os.path.join(self._main_prefix, self.EBOOK_DIR_MAIN))
-
- if self._card_a_prefix:
- storage.append(os.path.join(self._card_a_prefix, self.EBOOK_DIR_CARD_A))
-
- if self._card_b_prefix:
- storage.append(os.path.join(self._card_b_prefix, self.EBOOK_DIR_CARD_B))
-
- return storage
-
-
- def resolve_bookmark_paths(storage, path_map):
- pop_list = []
- book_ext = { }
- for id in path_map:
- file_fmts = set()
- for fmt in path_map[id]['fmts']:
- file_fmts.add(fmt)
-
- bookmark_extension = None
- if file_fmts.intersection(mbp_formats):
- book_extension = list(file_fmts.intersection(mbp_formats))[0]
- bookmark_extension = 'mbp'
- elif file_fmts.intersection(tan_formats):
- book_extension = list(file_fmts.intersection(tan_formats))[0]
- bookmark_extension = 'tan'
- elif file_fmts.intersection(pdr_formats):
- book_extension = list(file_fmts.intersection(pdr_formats))[0]
- bookmark_extension = 'pdr'
-
- if bookmark_extension:
- for vol in storage:
- bkmk_path = path_map[id]['path'].replace(os.path.abspath('/<storage>'), vol)
- bkmk_path = bkmk_path.replace('bookmark', bookmark_extension)
- if os.path.exists(bkmk_path):
- path_map[id] = bkmk_path
- book_ext[id] = book_extension
- break
- continue
-
- pop_list.append(id)
-
- for id in pop_list:
- path_map.pop(id)
-
- return (path_map, book_ext)
-
-
- def get_my_clippings(storage, bookmarked_books):
- for vol in storage:
- mc_path = os.path.join(vol, 'My Clippings.txt')
- if os.path.exists(mc_path):
- return mc_path
-
-
- storage = get_storage()
- (path_map, book_ext) = resolve_bookmark_paths(storage, path_map)
- bookmarked_books = { }
- for id in path_map:
- bookmark_ext = path_map[id].rpartition('.')[2]
- myBookmark = Bookmark(path_map[id], id, book_ext[id], bookmark_ext)
- bookmarked_books[id] = self.UserAnnotation(type = 'kindle_bookmark', value = myBookmark)
-
- mc_path = get_my_clippings(storage, bookmarked_books)
- if mc_path:
- timestamp = datetime.datetime.utcfromtimestamp(os.path.getmtime(mc_path))
- bookmarked_books['clippings'] = self.UserAnnotation(type = 'kindle_clippings', value = dict(path = mc_path, timestamp = timestamp))
-
- return bookmarked_books
-
-
-
- class KINDLE2(KINDLE):
- name = 'Kindle 2 Device Interface'
- description = _('Communicate with the Kindle 2 eBook reader.')
- FORMATS = KINDLE.FORMATS + [
- 'pdf']
- PRODUCT_ID = [
- 2]
- BCD = [
- 256]
-
- def books(self, oncard = None, end_session = True):
- bl = USBMS.books(self, oncard = oncard, end_session = end_session)
- collections = os.path.join(self._main_prefix, 'system', 'collections.json')
- if os.access(collections, os.R_OK):
-
- try:
- self.kindle_update_booklist(bl, collections)
- import traceback
- traceback.print_exc()
-
-
- return bl
-
-
- def kindle_update_booklist(self, bl, collections):
-
- try:
- f = _[1]
- collections = f.read()
- finally:
- pass
-
- collections = json.loads(collections)
- path_map = { }
- for name, val in collections.items():
- col = name.split('@')[0]
- items = val.get('items', [])
- for x in items:
- x = x[-40:]
- path_map[x].add(col)
-
-
- if path_map:
- for book in bl:
- path = '/mnt/us/' + book.lpath
- h = hashlib.sha1(path).hexdigest()
- if h in path_map:
- book.device_collections = list(sorted(path_map[h]))
- continue
- None if x not in path_map else open(collections, 'rb')
-
-
-
-
-
- class KINDLE_DX(KINDLE2):
- name = 'Kindle DX Device Interface'
- description = _('Communicate with the Kindle DX eBook reader.')
- PRODUCT_ID = [
- 3]
- BCD = [
- 256]
-
-
- class Bookmark:
-
- def __init__(self, path, id, book_format, bookmark_extension):
- self.book_format = book_format
- self.bookmark_extension = bookmark_extension
- self.book_length = 0
- self.id = id
- self.last_read = 0
- self.last_read_location = 0
- self.path = path
- self.timestamp = 0
- self.user_notes = None
- self.get_bookmark_data()
- self.get_book_length()
-
- try:
- self.percent_read = min(float(100 * self.last_read / self.book_length), 100)
- except:
- self.percent_read = 0
-
-
-
- def record(self, n):
- StreamSlicer = StreamSlicer
- import calibre.ebooks.metadata.mobi
- if n >= self.nrecs:
- raise ValueError('non-existent record %r' % n)
- n >= self.nrecs
- offoff = 78 + 8 * n
- (start,) = unpack('>I', self.data[offoff + 0:offoff + 4])
- stop = None
- if n < self.nrecs - 1:
- (stop,) = unpack('>I', self.data[offoff + 8:offoff + 12])
-
- return StreamSlicer(self.stream, start, stop)
-
-
- def get_bookmark_data(self):
- StreamSlicer = StreamSlicer
- import calibre.ebooks.metadata.mobi
- user_notes = { }
- if self.bookmark_extension == 'mbp':
- MAGIC_MOBI_CONSTANT = 150
-
- try:
- f = _[1]
- stream = StringIO(f.read())
- data = StreamSlicer(stream)
- (self.timestamp,) = unpack('>I', data[36:40])
- (bpar_offset,) = unpack('>I', data[78:82])
- lrlo = bpar_offset + 12
- self.last_read = int(unpack('>I', data[lrlo:lrlo + 4])[0])
- self.last_read_location = self.last_read / MAGIC_MOBI_CONSTANT + 1
- (entries,) = unpack('>I', data[74:78])
- bpl = bpar_offset + 4
- (bpar_len,) = unpack('>I', data[bpl:bpl + 4])
- bpar_len += 8
- eo = bpar_offset + bpar_len
- current_entry = 1
- sig = data[eo:eo + 4]
- previous_block = None
- while sig == 'DATA':
- text = None
- entry_type = None
- (rec_len,) = unpack('>I', data[eo + 4:eo + 8])
- if rec_len == 0:
- current_block = 'empty_data'
- elif data[eo + 8:eo + 12] == 'EBAR':
- current_block = 'data_header'
- (location,) = unpack('>I', data[eo + 52:eo + 56])
- else:
- current_block = 'text_block'
- if previous_block == 'empty_data':
- entry_type = 'Note'
- elif previous_block == 'data_header':
- entry_type = 'Highlight'
-
- text = data[eo + 8:eo + 8 + rec_len].decode('utf-16-be')
- if entry_type:
- displayed_location = location / MAGIC_MOBI_CONSTANT + 1
- user_notes[location] = dict(id = self.id, displayed_location = displayed_location, type = entry_type, text = text)
-
- eo += rec_len + 8
- current_entry += 1
- previous_block = current_block
- sig = data[eo:eo + 4]
- while sig == 'BKMK':
- (end_loc,) = unpack('>I', data[eo + 16:eo + 20])
- if end_loc in user_notes:
- if user_notes[end_loc]['type'] == 'Highlight' or user_notes[end_loc]['type'] == 'Note':
- (start,) = unpack('>I', data[eo + 8:eo + 12])
- user_notes[start] = user_notes[end_loc]
- user_notes[start]['displayed_location'] = start / MAGIC_MOBI_CONSTANT + 1
- user_notes.pop(end_loc)
- elif end_loc != self.last_read:
- displayed_location = end_loc / MAGIC_MOBI_CONSTANT + 1
- user_notes[end_loc - 1] = dict(id = self.id, displayed_location = displayed_location, type = 'Bookmark', text = None)
-
- (rec_len,) = unpack('>I', data[eo + 4:eo + 8])
- eo += rec_len + 8
- sig = data[eo:eo + 4]
- finally:
- pass
-
- elif self.bookmark_extension == 'tan':
- get_topaz_metadata = get_metadata
- import calibre.ebooks.metadata.topaz
-
- def get_topaz_highlight(displayed_location):
- book_fs = self.path.replace('.%s' % self.bookmark_extension, '.%s' % self.book_format)
-
- try:
- f2 = _[1]
- stream = StringIO(f2.read())
- mi = get_topaz_metadata(stream)
- finally:
- pass
-
- my_clippings = self.path
- split = my_clippings.find('documents') + len('documents/')
- my_clippings = my_clippings[:split] + 'My Clippings.txt'
-
- try:
-
- try:
- f2 = _[2]
- marker_found = 0
- text = ''
- search_str1 = '%s' % mi.title
- search_str2 = '- Highlight Loc. %d' % displayed_location
- for line in f2:
- if marker_found == 0:
- if line.startswith(search_str1):
- marker_found = 1
-
- line.startswith(search_str1)
- if marker_found == 1:
- if line.startswith(search_str2):
- marker_found = 2
-
- line.startswith(search_str2)
- if marker_found == 2:
- text += line.strip()
- continue
- open(book_fs, 'rb').__exit__ if line.startswith('==========') else open(my_clippings, 'r')
- else:
- raise Exception('error')
- finally:
- pass
- open(my_clippings, 'r')
- open(book_fs, 'rb').__exit__
- text = '(Unable to extract highlight text from My Clippings.txt)'
- return text
-
-
-
- MAGIC_TOPAZ_CONSTANT = 33.33
- self.timestamp = os.path.getmtime(self.path)
-
- try:
- f = _[2]
- stream = StringIO(f.read())
- data = StreamSlicer(stream)
- self.last_read = int(unpack('>I', data[5:9])[0])
- self.last_read_location = self.last_read / MAGIC_TOPAZ_CONSTANT + 1
- (entries,) = unpack('>I', data[9:13])
- current_entry = 0
- e_base = 13
- while current_entry < entries:
- (location,) = unpack('>I', data[e_base + 2:e_base + 6])
- text = None
- (text_len,) = unpack('>I', data[e_base + 10:e_base + 14])
- (e_type,) = unpack('>B', data[e_base + 1])
- if e_type == 0:
- e_type = 'Bookmark'
- elif e_type == 1:
- e_type = 'Highlight'
- text = get_topaz_highlight(location / MAGIC_TOPAZ_CONSTANT + 1)
- elif e_type == 2:
- e_type = 'Note'
- text = data[e_base + 16:e_base + 16 + text_len]
- else:
- e_type = 'Unknown annotation type'
- displayed_location = location / MAGIC_TOPAZ_CONSTANT + 1
- user_notes[location] = dict(id = self.id, displayed_location = displayed_location, type = e_type, text = text)
- if text_len == 0xFFFFFFFFL:
- e_base = e_base + 14
- else:
- e_base = e_base + 14 + 2 + text_len
- current_entry += 1
- for location in user_notes:
- if location == self.last_read:
- user_notes.pop(location)
- break
- continue
- finally:
- pass
-
- elif self.bookmark_extension == 'pdr':
- self.timestamp = os.path.getmtime(self.path)
-
- try:
- f = _[3]
- stream = StringIO(f.read())
- data = StreamSlicer(stream)
- self.last_read = int(unpack('>I', data[5:9])[0])
- (entries,) = unpack('>I', data[9:13])
- current_entry = 0
- e_base = 13
- self.pdf_page_offset = 0
- while current_entry < entries:
- (pdf_location,) = unpack('>I', data[e_base + 1:e_base + 5])
- (label_len,) = unpack('>H', data[e_base + 5:e_base + 7])
- location = int(data[e_base + 7:e_base + 7 + label_len])
- displayed_location = location
- e_type = 'Bookmark'
- text = None
- user_notes[location] = dict(id = self.id, displayed_location = displayed_location, type = e_type, text = text)
- self.pdf_page_offset = pdf_location - location
- e_base += 7 + label_len
- current_entry += 1
- continue
- open(self.path, 'rb').__exit__
- self.last_read_location = self.last_read - self.pdf_page_offset
- finally:
- pass
-
- else:
- print 'unsupported bookmark_extension: %s' % self.bookmark_extension
- self.user_notes = user_notes
-
-
- def get_book_length(self):
- StreamSlicer = StreamSlicer
- import calibre.ebooks.metadata.mobi
- book_fs = self.path.replace('.%s' % self.bookmark_extension, '.%s' % self.book_format)
- self.book_length = 0
- if self.bookmark_extension == 'mbp':
-
- try:
-
- try:
- f = _[1]
- self.stream = StringIO(f.read())
- self.data = StreamSlicer(self.stream)
- (self.nrecs,) = unpack('>H', self.data[76:78])
- record0 = self.record(0)
- self.book_length = int(unpack('>I', record0[4:8])[0])
- finally:
- pass
-
-
- elif self.bookmark_extension == 'tan':
- MetadataUpdater = MetadataUpdater
- import calibre.ebooks.metadata.topaz
-
- try:
-
- try:
- f = _[2]
- mu = MetadataUpdater(f)
- self.book_length = mu.book_length
- finally:
- pass
-
-
- elif self.bookmark_extension == 'pdr':
- plugins = plugins
- import calibre
-
- try:
- self.book_length = plugins['pdfreflow'][0].get_numpages(open(book_fs).read())
-
- else:
- print 'unsupported bookmark_extension: %s' % self.bookmark_extension
-
-
-