home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 January / maximum-cd-2011-01.iso / DiscContents / calibre-0.7.26.msi / file_766 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-10-31  |  14.0 KB  |  505 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. __license__ = 'GPL v3'
  5. __copyright__ = '2009, John Schember <john at nachtimwald.com>'
  6. __docformat__ = 'restructuredtext en'
  7. import datetime
  8. import os
  9. import re
  10. import sys
  11. import json
  12. import hashlib
  13. from cStringIO import StringIO
  14. from struct import unpack
  15. from calibre.devices.usbms.driver import USBMS
  16.  
  17. class KINDLE(USBMS):
  18.     name = 'Kindle Device Interface'
  19.     gui_name = 'Amazon Kindle'
  20.     icon = I('devices/kindle.jpg')
  21.     description = _('Communicate with the Kindle eBook reader.')
  22.     author = 'John Schember'
  23.     supported_platforms = [
  24.         'windows',
  25.         'osx',
  26.         'linux']
  27.     FORMATS = [
  28.         'azw',
  29.         'mobi',
  30.         'prc',
  31.         'azw1',
  32.         'tpz',
  33.         'txt']
  34.     VENDOR_ID = [
  35.         6473]
  36.     PRODUCT_ID = [
  37.         1]
  38.     BCD = [
  39.         921]
  40.     VENDOR_NAME = 'KINDLE'
  41.     WINDOWS_MAIN_MEM = 'INTERNAL_STORAGE'
  42.     WINDOWS_CARD_A_MEM = 'CARD_STORAGE'
  43.     OSX_MAIN_MEM = 'Kindle Internal Storage Media'
  44.     OSX_CARD_A_MEM = 'Kindle Card Storage Media'
  45.     MAIN_MEMORY_VOLUME_LABEL = 'Kindle Main Memory'
  46.     STORAGE_CARD_VOLUME_LABEL = 'Kindle Storage Card'
  47.     EBOOK_DIR_MAIN = 'documents'
  48.     EBOOK_DIR_CARD_A = 'documents'
  49.     DELETE_EXTS = [
  50.         '.mbp',
  51.         '.tan',
  52.         '.pdr']
  53.     SUPPORTS_SUB_DIRS = True
  54.     SUPPORTS_ANNOTATIONS = True
  55.     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+).*')
  56.     
  57.     def metadata_from_path(cls, path):
  58.         mi = cls.metadata_from_formats([
  59.             path])
  60.         if (mi.title == _('Unknown') or '-asin' in mi.title) and '-type' in mi.title:
  61.             match = cls.WIRELESS_FILE_NAME_PATTERN.match(os.path.basename(path))
  62.             if match is not None:
  63.                 mi.title = match.group('title')
  64.                 if not isinstance(mi.title, unicode):
  65.                     mi.title = mi.title.decode(sys.getfilesystemencoding(), 'replace')
  66.                 
  67.             
  68.         
  69.         return mi
  70.  
  71.     metadata_from_path = classmethod(metadata_from_path)
  72.     
  73.     def get_annotations(self, path_map):
  74.         MBP_FORMATS = [
  75.             u'azw',
  76.             u'mobi',
  77.             u'prc',
  78.             u'txt']
  79.         mbp_formats = set(MBP_FORMATS)
  80.         PDR_FORMATS = [
  81.             u'pdf']
  82.         pdr_formats = set(PDR_FORMATS)
  83.         TAN_FORMATS = [
  84.             u'tpz',
  85.             u'azw1']
  86.         tan_formats = set(TAN_FORMATS)
  87.         
  88.         def get_storage():
  89.             storage = []
  90.             if self._main_prefix:
  91.                 storage.append(os.path.join(self._main_prefix, self.EBOOK_DIR_MAIN))
  92.             
  93.             if self._card_a_prefix:
  94.                 storage.append(os.path.join(self._card_a_prefix, self.EBOOK_DIR_CARD_A))
  95.             
  96.             if self._card_b_prefix:
  97.                 storage.append(os.path.join(self._card_b_prefix, self.EBOOK_DIR_CARD_B))
  98.             
  99.             return storage
  100.  
  101.         
  102.         def resolve_bookmark_paths(storage, path_map):
  103.             pop_list = []
  104.             book_ext = { }
  105.             for id in path_map:
  106.                 file_fmts = set()
  107.                 for fmt in path_map[id]['fmts']:
  108.                     file_fmts.add(fmt)
  109.                 
  110.                 bookmark_extension = None
  111.                 if file_fmts.intersection(mbp_formats):
  112.                     book_extension = list(file_fmts.intersection(mbp_formats))[0]
  113.                     bookmark_extension = 'mbp'
  114.                 elif file_fmts.intersection(tan_formats):
  115.                     book_extension = list(file_fmts.intersection(tan_formats))[0]
  116.                     bookmark_extension = 'tan'
  117.                 elif file_fmts.intersection(pdr_formats):
  118.                     book_extension = list(file_fmts.intersection(pdr_formats))[0]
  119.                     bookmark_extension = 'pdr'
  120.                 
  121.                 if bookmark_extension:
  122.                     for vol in storage:
  123.                         bkmk_path = path_map[id]['path'].replace(os.path.abspath('/<storage>'), vol)
  124.                         bkmk_path = bkmk_path.replace('bookmark', bookmark_extension)
  125.                         if os.path.exists(bkmk_path):
  126.                             path_map[id] = bkmk_path
  127.                             book_ext[id] = book_extension
  128.                             break
  129.                             continue
  130.                     
  131.                 pop_list.append(id)
  132.             
  133.             for id in pop_list:
  134.                 path_map.pop(id)
  135.             
  136.             return (path_map, book_ext)
  137.  
  138.         
  139.         def get_my_clippings(storage, bookmarked_books):
  140.             for vol in storage:
  141.                 mc_path = os.path.join(vol, 'My Clippings.txt')
  142.                 if os.path.exists(mc_path):
  143.                     return mc_path
  144.             
  145.  
  146.         storage = get_storage()
  147.         (path_map, book_ext) = resolve_bookmark_paths(storage, path_map)
  148.         bookmarked_books = { }
  149.         for id in path_map:
  150.             bookmark_ext = path_map[id].rpartition('.')[2]
  151.             myBookmark = Bookmark(path_map[id], id, book_ext[id], bookmark_ext)
  152.             bookmarked_books[id] = self.UserAnnotation(type = 'kindle_bookmark', value = myBookmark)
  153.         
  154.         mc_path = get_my_clippings(storage, bookmarked_books)
  155.         if mc_path:
  156.             timestamp = datetime.datetime.utcfromtimestamp(os.path.getmtime(mc_path))
  157.             bookmarked_books['clippings'] = self.UserAnnotation(type = 'kindle_clippings', value = dict(path = mc_path, timestamp = timestamp))
  158.         
  159.         return bookmarked_books
  160.  
  161.  
  162.  
  163. class KINDLE2(KINDLE):
  164.     name = 'Kindle 2/3 Device Interface'
  165.     description = _('Communicate with the Kindle 2/3 eBook reader.')
  166.     FORMATS = KINDLE.FORMATS + [
  167.         'pdf']
  168.     PRODUCT_ID = [
  169.         2,
  170.         4]
  171.     BCD = [
  172.         256]
  173.     
  174.     def books(self, oncard = None, end_session = True):
  175.         bl = USBMS.books(self, oncard = oncard, end_session = end_session)
  176.         collections = os.path.join(self._main_prefix, 'system', 'collections.json')
  177.         if os.access(collections, os.R_OK):
  178.             
  179.             try:
  180.                 self.kindle_update_booklist(bl, collections)
  181.             import traceback
  182.             traceback.print_exc()
  183.  
  184.         
  185.         return bl
  186.  
  187.     
  188.     def kindle_update_booklist(self, bl, collections):
  189.         
  190.         try:
  191.             f = _[1]
  192.             collections = f.read()
  193.         finally:
  194.             pass
  195.  
  196.         collections = json.loads(collections)
  197.         path_map = { }
  198.         for name, val in collections.items():
  199.             col = name.split('@')[0]
  200.             items = val.get('items', [])
  201.             for x in items:
  202.                 x = x[-40:]
  203.                 path_map[x].add(col)
  204.             
  205.         
  206.         if path_map:
  207.             for book in bl:
  208.                 path = '/mnt/us/' + book.lpath
  209.                 h = hashlib.sha1(path).hexdigest()
  210.                 if h in path_map:
  211.                     book.device_collections = list(sorted(path_map[h]))
  212.                     continue
  213.                 None if x not in path_map else open(collections, 'rb')
  214.             
  215.         
  216.  
  217.  
  218.  
  219. class KINDLE_DX(KINDLE2):
  220.     name = 'Kindle DX Device Interface'
  221.     description = _('Communicate with the Kindle DX eBook reader.')
  222.     PRODUCT_ID = [
  223.         3]
  224.     BCD = [
  225.         256]
  226.  
  227.  
  228. class Bookmark:
  229.     
  230.     def __init__(self, path, id, book_format, bookmark_extension):
  231.         self.book_format = book_format
  232.         self.bookmark_extension = bookmark_extension
  233.         self.book_length = 0
  234.         self.id = id
  235.         self.last_read = 0
  236.         self.last_read_location = 0
  237.         self.path = path
  238.         self.timestamp = 0
  239.         self.user_notes = None
  240.         self.get_bookmark_data()
  241.         self.get_book_length()
  242.         
  243.         try:
  244.             self.percent_read = min(float(100 * self.last_read / self.book_length), 100)
  245.         except:
  246.             self.percent_read = 0
  247.  
  248.  
  249.     
  250.     def record(self, n):
  251.         StreamSlicer = StreamSlicer
  252.         import calibre.ebooks.metadata.mobi
  253.         if n >= self.nrecs:
  254.             raise ValueError('non-existent record %r' % n)
  255.         n >= self.nrecs
  256.         offoff = 78 + 8 * n
  257.         (start,) = unpack('>I', self.data[offoff + 0:offoff + 4])
  258.         stop = None
  259.         if n < self.nrecs - 1:
  260.             (stop,) = unpack('>I', self.data[offoff + 8:offoff + 12])
  261.         
  262.         return StreamSlicer(self.stream, start, stop)
  263.  
  264.     
  265.     def get_bookmark_data(self):
  266.         StreamSlicer = StreamSlicer
  267.         import calibre.ebooks.metadata.mobi
  268.         user_notes = { }
  269.         if self.bookmark_extension == 'mbp':
  270.             MAGIC_MOBI_CONSTANT = 150
  271.             
  272.             try:
  273.                 f = _[1]
  274.                 stream = StringIO(f.read())
  275.                 data = StreamSlicer(stream)
  276.                 (self.timestamp,) = unpack('>I', data[36:40])
  277.                 (bpar_offset,) = unpack('>I', data[78:82])
  278.                 lrlo = bpar_offset + 12
  279.                 self.last_read = int(unpack('>I', data[lrlo:lrlo + 4])[0])
  280.                 self.last_read_location = self.last_read / MAGIC_MOBI_CONSTANT + 1
  281.                 (entries,) = unpack('>I', data[74:78])
  282.                 bpl = bpar_offset + 4
  283.                 (bpar_len,) = unpack('>I', data[bpl:bpl + 4])
  284.                 bpar_len += 8
  285.                 eo = bpar_offset + bpar_len
  286.                 current_entry = 1
  287.                 sig = data[eo:eo + 4]
  288.                 previous_block = None
  289.                 while sig == 'DATA':
  290.                     text = None
  291.                     entry_type = None
  292.                     (rec_len,) = unpack('>I', data[eo + 4:eo + 8])
  293.                     if rec_len == 0:
  294.                         current_block = 'empty_data'
  295.                     elif data[eo + 8:eo + 12] == 'EBAR':
  296.                         current_block = 'data_header'
  297.                         (location,) = unpack('>I', data[eo + 52:eo + 56])
  298.                     else:
  299.                         current_block = 'text_block'
  300.                         if previous_block == 'empty_data':
  301.                             entry_type = 'Note'
  302.                         elif previous_block == 'data_header':
  303.                             entry_type = 'Highlight'
  304.                         
  305.                         text = data[eo + 8:eo + 8 + rec_len].decode('utf-16-be')
  306.                     if entry_type:
  307.                         displayed_location = location / MAGIC_MOBI_CONSTANT + 1
  308.                         user_notes[location] = dict(id = self.id, displayed_location = displayed_location, type = entry_type, text = text)
  309.                     
  310.                     eo += rec_len + 8
  311.                     current_entry += 1
  312.                     previous_block = current_block
  313.                     sig = data[eo:eo + 4]
  314.                 while sig == 'BKMK':
  315.                     (end_loc,) = unpack('>I', data[eo + 16:eo + 20])
  316.                     if end_loc in user_notes:
  317.                         if user_notes[end_loc]['type'] == 'Highlight' or user_notes[end_loc]['type'] == 'Note':
  318.                             (start,) = unpack('>I', data[eo + 8:eo + 12])
  319.                             user_notes[start] = user_notes[end_loc]
  320.                             user_notes[start]['displayed_location'] = start / MAGIC_MOBI_CONSTANT + 1
  321.                             user_notes.pop(end_loc)
  322.                         elif end_loc != self.last_read:
  323.                             displayed_location = end_loc / MAGIC_MOBI_CONSTANT + 1
  324.                             user_notes[end_loc - 1] = dict(id = self.id, displayed_location = displayed_location, type = 'Bookmark', text = None)
  325.                         
  326.                     (rec_len,) = unpack('>I', data[eo + 4:eo + 8])
  327.                     eo += rec_len + 8
  328.                     sig = data[eo:eo + 4]
  329.             finally:
  330.                 pass
  331.  
  332.         elif self.bookmark_extension == 'tan':
  333.             get_topaz_metadata = get_metadata
  334.             import calibre.ebooks.metadata.topaz
  335.             
  336.             def get_topaz_highlight(displayed_location):
  337.                 book_fs = self.path.replace('.%s' % self.bookmark_extension, '.%s' % self.book_format)
  338.                 
  339.                 try:
  340.                     f2 = _[1]
  341.                     stream = StringIO(f2.read())
  342.                     mi = get_topaz_metadata(stream)
  343.                 finally:
  344.                     pass
  345.  
  346.                 my_clippings = self.path
  347.                 split = my_clippings.find('documents') + len('documents/')
  348.                 my_clippings = my_clippings[:split] + 'My Clippings.txt'
  349.                 
  350.                 try:
  351.                     
  352.                     try:
  353.                         f2 = _[2]
  354.                         marker_found = 0
  355.                         text = ''
  356.                         search_str1 = '%s' % mi.title
  357.                         search_str2 = '- Highlight Loc. %d' % displayed_location
  358.                         for line in f2:
  359.                             if marker_found == 0:
  360.                                 if line.startswith(search_str1):
  361.                                     marker_found = 1
  362.                                 
  363.                             line.startswith(search_str1)
  364.                             if marker_found == 1:
  365.                                 if line.startswith(search_str2):
  366.                                     marker_found = 2
  367.                                 
  368.                             line.startswith(search_str2)
  369.                             if marker_found == 2:
  370.                                 text += line.strip()
  371.                                 continue
  372.                             open(book_fs, 'rb').__exit__ if line.startswith('==========') else open(my_clippings, 'r')
  373.                         else:
  374.                             raise Exception('error')
  375.                     finally:
  376.                         pass
  377.                     open(my_clippings, 'r')
  378.                     open(book_fs, 'rb').__exit__
  379.                     text = '(Unable to extract highlight text from My Clippings.txt)'
  380.                     return text
  381.  
  382.  
  383.  
  384.             MAGIC_TOPAZ_CONSTANT = 33.33
  385.             self.timestamp = os.path.getmtime(self.path)
  386.             
  387.             try:
  388.                 f = _[2]
  389.                 stream = StringIO(f.read())
  390.                 data = StreamSlicer(stream)
  391.                 self.last_read = int(unpack('>I', data[5:9])[0])
  392.                 self.last_read_location = self.last_read / MAGIC_TOPAZ_CONSTANT + 1
  393.                 (entries,) = unpack('>I', data[9:13])
  394.                 current_entry = 0
  395.                 e_base = 13
  396.                 while current_entry < entries:
  397.                     (location,) = unpack('>I', data[e_base + 2:e_base + 6])
  398.                     text = None
  399.                     (text_len,) = unpack('>I', data[e_base + 10:e_base + 14])
  400.                     (e_type,) = unpack('>B', data[e_base + 1])
  401.                     if e_type == 0:
  402.                         e_type = 'Bookmark'
  403.                     elif e_type == 1:
  404.                         e_type = 'Highlight'
  405.                         text = get_topaz_highlight(location / MAGIC_TOPAZ_CONSTANT + 1)
  406.                     elif e_type == 2:
  407.                         e_type = 'Note'
  408.                         text = data[e_base + 16:e_base + 16 + text_len]
  409.                     else:
  410.                         e_type = 'Unknown annotation type'
  411.                     displayed_location = location / MAGIC_TOPAZ_CONSTANT + 1
  412.                     user_notes[location] = dict(id = self.id, displayed_location = displayed_location, type = e_type, text = text)
  413.                     if text_len == 0xFFFFFFFFL:
  414.                         e_base = e_base + 14
  415.                     else:
  416.                         e_base = e_base + 14 + 2 + text_len
  417.                     current_entry += 1
  418.                 for location in user_notes:
  419.                     if location == self.last_read:
  420.                         user_notes.pop(location)
  421.                         break
  422.                         continue
  423.             finally:
  424.                 pass
  425.  
  426.         elif self.bookmark_extension == 'pdr':
  427.             self.timestamp = os.path.getmtime(self.path)
  428.             
  429.             try:
  430.                 f = _[3]
  431.                 stream = StringIO(f.read())
  432.                 data = StreamSlicer(stream)
  433.                 self.last_read = int(unpack('>I', data[5:9])[0])
  434.                 (entries,) = unpack('>I', data[9:13])
  435.                 current_entry = 0
  436.                 e_base = 13
  437.                 self.pdf_page_offset = 0
  438.                 while current_entry < entries:
  439.                     (pdf_location,) = unpack('>I', data[e_base + 1:e_base + 5])
  440.                     (label_len,) = unpack('>H', data[e_base + 5:e_base + 7])
  441.                     location = int(data[e_base + 7:e_base + 7 + label_len])
  442.                     displayed_location = location
  443.                     e_type = 'Bookmark'
  444.                     text = None
  445.                     user_notes[location] = dict(id = self.id, displayed_location = displayed_location, type = e_type, text = text)
  446.                     self.pdf_page_offset = pdf_location - location
  447.                     e_base += 7 + label_len
  448.                     current_entry += 1
  449.                     continue
  450.                     open(self.path, 'rb').__exit__
  451.                 self.last_read_location = self.last_read - self.pdf_page_offset
  452.             finally:
  453.                 pass
  454.  
  455.         else:
  456.             print 'unsupported bookmark_extension: %s' % self.bookmark_extension
  457.         self.user_notes = user_notes
  458.  
  459.     
  460.     def get_book_length(self):
  461.         StreamSlicer = StreamSlicer
  462.         import calibre.ebooks.metadata.mobi
  463.         book_fs = self.path.replace('.%s' % self.bookmark_extension, '.%s' % self.book_format)
  464.         self.book_length = 0
  465.         if self.bookmark_extension == 'mbp':
  466.             
  467.             try:
  468.                 
  469.                 try:
  470.                     f = _[1]
  471.                     self.stream = StringIO(f.read())
  472.                     self.data = StreamSlicer(self.stream)
  473.                     (self.nrecs,) = unpack('>H', self.data[76:78])
  474.                     record0 = self.record(0)
  475.                     self.book_length = int(unpack('>I', record0[4:8])[0])
  476.                 finally:
  477.                     pass
  478.  
  479.  
  480.         elif self.bookmark_extension == 'tan':
  481.             MetadataUpdater = MetadataUpdater
  482.             import calibre.ebooks.metadata.topaz
  483.             
  484.             try:
  485.                 
  486.                 try:
  487.                     f = _[2]
  488.                     mu = MetadataUpdater(f)
  489.                     self.book_length = mu.book_length
  490.                 finally:
  491.                     pass
  492.  
  493.  
  494.         elif self.bookmark_extension == 'pdr':
  495.             plugins = plugins
  496.             import calibre
  497.             
  498.             try:
  499.                 self.book_length = plugins['pdfreflow'][0].get_numpages(open(book_fs).read())
  500.  
  501.         else:
  502.             print 'unsupported bookmark_extension: %s' % self.bookmark_extension
  503.  
  504.  
  505.