home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_774 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  14.0 KB  |  504 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 Device Interface'
  165.     description = _('Communicate with the Kindle 2 eBook reader.')
  166.     FORMATS = KINDLE.FORMATS + [
  167.         'pdf']
  168.     PRODUCT_ID = [
  169.         2]
  170.     BCD = [
  171.         256]
  172.     
  173.     def books(self, oncard = None, end_session = True):
  174.         bl = USBMS.books(self, oncard = oncard, end_session = end_session)
  175.         collections = os.path.join(self._main_prefix, 'system', 'collections.json')
  176.         if os.access(collections, os.R_OK):
  177.             
  178.             try:
  179.                 self.kindle_update_booklist(bl, collections)
  180.             import traceback
  181.             traceback.print_exc()
  182.  
  183.         
  184.         return bl
  185.  
  186.     
  187.     def kindle_update_booklist(self, bl, collections):
  188.         
  189.         try:
  190.             f = _[1]
  191.             collections = f.read()
  192.         finally:
  193.             pass
  194.  
  195.         collections = json.loads(collections)
  196.         path_map = { }
  197.         for name, val in collections.items():
  198.             col = name.split('@')[0]
  199.             items = val.get('items', [])
  200.             for x in items:
  201.                 x = x[-40:]
  202.                 path_map[x].add(col)
  203.             
  204.         
  205.         if path_map:
  206.             for book in bl:
  207.                 path = '/mnt/us/' + book.lpath
  208.                 h = hashlib.sha1(path).hexdigest()
  209.                 if h in path_map:
  210.                     book.device_collections = list(sorted(path_map[h]))
  211.                     continue
  212.                 None if x not in path_map else open(collections, 'rb')
  213.             
  214.         
  215.  
  216.  
  217.  
  218. class KINDLE_DX(KINDLE2):
  219.     name = 'Kindle DX Device Interface'
  220.     description = _('Communicate with the Kindle DX eBook reader.')
  221.     PRODUCT_ID = [
  222.         3]
  223.     BCD = [
  224.         256]
  225.  
  226.  
  227. class Bookmark:
  228.     
  229.     def __init__(self, path, id, book_format, bookmark_extension):
  230.         self.book_format = book_format
  231.         self.bookmark_extension = bookmark_extension
  232.         self.book_length = 0
  233.         self.id = id
  234.         self.last_read = 0
  235.         self.last_read_location = 0
  236.         self.path = path
  237.         self.timestamp = 0
  238.         self.user_notes = None
  239.         self.get_bookmark_data()
  240.         self.get_book_length()
  241.         
  242.         try:
  243.             self.percent_read = min(float(100 * self.last_read / self.book_length), 100)
  244.         except:
  245.             self.percent_read = 0
  246.  
  247.  
  248.     
  249.     def record(self, n):
  250.         StreamSlicer = StreamSlicer
  251.         import calibre.ebooks.metadata.mobi
  252.         if n >= self.nrecs:
  253.             raise ValueError('non-existent record %r' % n)
  254.         n >= self.nrecs
  255.         offoff = 78 + 8 * n
  256.         (start,) = unpack('>I', self.data[offoff + 0:offoff + 4])
  257.         stop = None
  258.         if n < self.nrecs - 1:
  259.             (stop,) = unpack('>I', self.data[offoff + 8:offoff + 12])
  260.         
  261.         return StreamSlicer(self.stream, start, stop)
  262.  
  263.     
  264.     def get_bookmark_data(self):
  265.         StreamSlicer = StreamSlicer
  266.         import calibre.ebooks.metadata.mobi
  267.         user_notes = { }
  268.         if self.bookmark_extension == 'mbp':
  269.             MAGIC_MOBI_CONSTANT = 150
  270.             
  271.             try:
  272.                 f = _[1]
  273.                 stream = StringIO(f.read())
  274.                 data = StreamSlicer(stream)
  275.                 (self.timestamp,) = unpack('>I', data[36:40])
  276.                 (bpar_offset,) = unpack('>I', data[78:82])
  277.                 lrlo = bpar_offset + 12
  278.                 self.last_read = int(unpack('>I', data[lrlo:lrlo + 4])[0])
  279.                 self.last_read_location = self.last_read / MAGIC_MOBI_CONSTANT + 1
  280.                 (entries,) = unpack('>I', data[74:78])
  281.                 bpl = bpar_offset + 4
  282.                 (bpar_len,) = unpack('>I', data[bpl:bpl + 4])
  283.                 bpar_len += 8
  284.                 eo = bpar_offset + bpar_len
  285.                 current_entry = 1
  286.                 sig = data[eo:eo + 4]
  287.                 previous_block = None
  288.                 while sig == 'DATA':
  289.                     text = None
  290.                     entry_type = None
  291.                     (rec_len,) = unpack('>I', data[eo + 4:eo + 8])
  292.                     if rec_len == 0:
  293.                         current_block = 'empty_data'
  294.                     elif data[eo + 8:eo + 12] == 'EBAR':
  295.                         current_block = 'data_header'
  296.                         (location,) = unpack('>I', data[eo + 52:eo + 56])
  297.                     else:
  298.                         current_block = 'text_block'
  299.                         if previous_block == 'empty_data':
  300.                             entry_type = 'Note'
  301.                         elif previous_block == 'data_header':
  302.                             entry_type = 'Highlight'
  303.                         
  304.                         text = data[eo + 8:eo + 8 + rec_len].decode('utf-16-be')
  305.                     if entry_type:
  306.                         displayed_location = location / MAGIC_MOBI_CONSTANT + 1
  307.                         user_notes[location] = dict(id = self.id, displayed_location = displayed_location, type = entry_type, text = text)
  308.                     
  309.                     eo += rec_len + 8
  310.                     current_entry += 1
  311.                     previous_block = current_block
  312.                     sig = data[eo:eo + 4]
  313.                 while sig == 'BKMK':
  314.                     (end_loc,) = unpack('>I', data[eo + 16:eo + 20])
  315.                     if end_loc in user_notes:
  316.                         if user_notes[end_loc]['type'] == 'Highlight' or user_notes[end_loc]['type'] == 'Note':
  317.                             (start,) = unpack('>I', data[eo + 8:eo + 12])
  318.                             user_notes[start] = user_notes[end_loc]
  319.                             user_notes[start]['displayed_location'] = start / MAGIC_MOBI_CONSTANT + 1
  320.                             user_notes.pop(end_loc)
  321.                         elif end_loc != self.last_read:
  322.                             displayed_location = end_loc / MAGIC_MOBI_CONSTANT + 1
  323.                             user_notes[end_loc - 1] = dict(id = self.id, displayed_location = displayed_location, type = 'Bookmark', text = None)
  324.                         
  325.                     (rec_len,) = unpack('>I', data[eo + 4:eo + 8])
  326.                     eo += rec_len + 8
  327.                     sig = data[eo:eo + 4]
  328.             finally:
  329.                 pass
  330.  
  331.         elif self.bookmark_extension == 'tan':
  332.             get_topaz_metadata = get_metadata
  333.             import calibre.ebooks.metadata.topaz
  334.             
  335.             def get_topaz_highlight(displayed_location):
  336.                 book_fs = self.path.replace('.%s' % self.bookmark_extension, '.%s' % self.book_format)
  337.                 
  338.                 try:
  339.                     f2 = _[1]
  340.                     stream = StringIO(f2.read())
  341.                     mi = get_topaz_metadata(stream)
  342.                 finally:
  343.                     pass
  344.  
  345.                 my_clippings = self.path
  346.                 split = my_clippings.find('documents') + len('documents/')
  347.                 my_clippings = my_clippings[:split] + 'My Clippings.txt'
  348.                 
  349.                 try:
  350.                     
  351.                     try:
  352.                         f2 = _[2]
  353.                         marker_found = 0
  354.                         text = ''
  355.                         search_str1 = '%s' % mi.title
  356.                         search_str2 = '- Highlight Loc. %d' % displayed_location
  357.                         for line in f2:
  358.                             if marker_found == 0:
  359.                                 if line.startswith(search_str1):
  360.                                     marker_found = 1
  361.                                 
  362.                             line.startswith(search_str1)
  363.                             if marker_found == 1:
  364.                                 if line.startswith(search_str2):
  365.                                     marker_found = 2
  366.                                 
  367.                             line.startswith(search_str2)
  368.                             if marker_found == 2:
  369.                                 text += line.strip()
  370.                                 continue
  371.                             open(book_fs, 'rb').__exit__ if line.startswith('==========') else open(my_clippings, 'r')
  372.                         else:
  373.                             raise Exception('error')
  374.                     finally:
  375.                         pass
  376.                     open(my_clippings, 'r')
  377.                     open(book_fs, 'rb').__exit__
  378.                     text = '(Unable to extract highlight text from My Clippings.txt)'
  379.                     return text
  380.  
  381.  
  382.  
  383.             MAGIC_TOPAZ_CONSTANT = 33.33
  384.             self.timestamp = os.path.getmtime(self.path)
  385.             
  386.             try:
  387.                 f = _[2]
  388.                 stream = StringIO(f.read())
  389.                 data = StreamSlicer(stream)
  390.                 self.last_read = int(unpack('>I', data[5:9])[0])
  391.                 self.last_read_location = self.last_read / MAGIC_TOPAZ_CONSTANT + 1
  392.                 (entries,) = unpack('>I', data[9:13])
  393.                 current_entry = 0
  394.                 e_base = 13
  395.                 while current_entry < entries:
  396.                     (location,) = unpack('>I', data[e_base + 2:e_base + 6])
  397.                     text = None
  398.                     (text_len,) = unpack('>I', data[e_base + 10:e_base + 14])
  399.                     (e_type,) = unpack('>B', data[e_base + 1])
  400.                     if e_type == 0:
  401.                         e_type = 'Bookmark'
  402.                     elif e_type == 1:
  403.                         e_type = 'Highlight'
  404.                         text = get_topaz_highlight(location / MAGIC_TOPAZ_CONSTANT + 1)
  405.                     elif e_type == 2:
  406.                         e_type = 'Note'
  407.                         text = data[e_base + 16:e_base + 16 + text_len]
  408.                     else:
  409.                         e_type = 'Unknown annotation type'
  410.                     displayed_location = location / MAGIC_TOPAZ_CONSTANT + 1
  411.                     user_notes[location] = dict(id = self.id, displayed_location = displayed_location, type = e_type, text = text)
  412.                     if text_len == 0xFFFFFFFFL:
  413.                         e_base = e_base + 14
  414.                     else:
  415.                         e_base = e_base + 14 + 2 + text_len
  416.                     current_entry += 1
  417.                 for location in user_notes:
  418.                     if location == self.last_read:
  419.                         user_notes.pop(location)
  420.                         break
  421.                         continue
  422.             finally:
  423.                 pass
  424.  
  425.         elif self.bookmark_extension == 'pdr':
  426.             self.timestamp = os.path.getmtime(self.path)
  427.             
  428.             try:
  429.                 f = _[3]
  430.                 stream = StringIO(f.read())
  431.                 data = StreamSlicer(stream)
  432.                 self.last_read = int(unpack('>I', data[5:9])[0])
  433.                 (entries,) = unpack('>I', data[9:13])
  434.                 current_entry = 0
  435.                 e_base = 13
  436.                 self.pdf_page_offset = 0
  437.                 while current_entry < entries:
  438.                     (pdf_location,) = unpack('>I', data[e_base + 1:e_base + 5])
  439.                     (label_len,) = unpack('>H', data[e_base + 5:e_base + 7])
  440.                     location = int(data[e_base + 7:e_base + 7 + label_len])
  441.                     displayed_location = location
  442.                     e_type = 'Bookmark'
  443.                     text = None
  444.                     user_notes[location] = dict(id = self.id, displayed_location = displayed_location, type = e_type, text = text)
  445.                     self.pdf_page_offset = pdf_location - location
  446.                     e_base += 7 + label_len
  447.                     current_entry += 1
  448.                     continue
  449.                     open(self.path, 'rb').__exit__
  450.                 self.last_read_location = self.last_read - self.pdf_page_offset
  451.             finally:
  452.                 pass
  453.  
  454.         else:
  455.             print 'unsupported bookmark_extension: %s' % self.bookmark_extension
  456.         self.user_notes = user_notes
  457.  
  458.     
  459.     def get_book_length(self):
  460.         StreamSlicer = StreamSlicer
  461.         import calibre.ebooks.metadata.mobi
  462.         book_fs = self.path.replace('.%s' % self.bookmark_extension, '.%s' % self.book_format)
  463.         self.book_length = 0
  464.         if self.bookmark_extension == 'mbp':
  465.             
  466.             try:
  467.                 
  468.                 try:
  469.                     f = _[1]
  470.                     self.stream = StringIO(f.read())
  471.                     self.data = StreamSlicer(self.stream)
  472.                     (self.nrecs,) = unpack('>H', self.data[76:78])
  473.                     record0 = self.record(0)
  474.                     self.book_length = int(unpack('>I', record0[4:8])[0])
  475.                 finally:
  476.                     pass
  477.  
  478.  
  479.         elif self.bookmark_extension == 'tan':
  480.             MetadataUpdater = MetadataUpdater
  481.             import calibre.ebooks.metadata.topaz
  482.             
  483.             try:
  484.                 
  485.                 try:
  486.                     f = _[2]
  487.                     mu = MetadataUpdater(f)
  488.                     self.book_length = mu.book_length
  489.                 finally:
  490.                     pass
  491.  
  492.  
  493.         elif self.bookmark_extension == 'pdr':
  494.             plugins = plugins
  495.             import calibre
  496.             
  497.             try:
  498.                 self.book_length = plugins['pdfreflow'][0].get_numpages(open(book_fs).read())
  499.  
  500.         else:
  501.             print 'unsupported bookmark_extension: %s' % self.bookmark_extension
  502.  
  503.  
  504.