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

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. __license__ = 'GPL v3'
  5. __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
  6. __docformat__ = 'restructuredtext en'
  7. import re
  8. import os
  9. import traceback
  10. import shutil
  11. from threading import Thread
  12. from operator import itemgetter
  13. from calibre.ptempfile import TemporaryDirectory
  14. from calibre.ebooks.metadata.opf2 import OPF
  15. from calibre.library.database2 import LibraryDatabase2
  16. from calibre.constants import filesystem_encoding
  17. from calibre import isbytestring
  18. NON_EBOOK_EXTENSIONS = frozenset([
  19.     'jpg',
  20.     'jpeg',
  21.     'gif',
  22.     'png',
  23.     'bmp',
  24.     'opf',
  25.     'swp',
  26.     'swo'])
  27.  
  28. class RestoreDatabase(LibraryDatabase2):
  29.     PATH_LIMIT = 10
  30.     
  31.     def set_path(self, *args, **kwargs):
  32.         pass
  33.  
  34.     
  35.     def dirtied(self, *args, **kwargs):
  36.         pass
  37.  
  38.  
  39.  
  40. class Restore(Thread):
  41.     
  42.     def __init__(self, library_path, progress_callback = None):
  43.         super(Restore, self).__init__()
  44.         if isbytestring(library_path):
  45.             library_path = library_path.decode(filesystem_encoding)
  46.         
  47.         self.src_library_path = os.path.abspath(library_path)
  48.         self.progress_callback = progress_callback
  49.         self.db_id_regexp = re.compile('^.* \\((\\d+)\\)$')
  50.         self.bad_ext_pat = re.compile('[^a-z0-9]+')
  51.         if not callable(self.progress_callback):
  52.             
  53.             self.progress_callback = lambda x, y: x
  54.         
  55.         self.dirs = []
  56.         self.ignored_dirs = []
  57.         self.failed_dirs = []
  58.         self.books = []
  59.         self.conflicting_custom_cols = { }
  60.         self.failed_restores = []
  61.         self.mismatched_dirs = []
  62.         self.successes = 0
  63.         self.tb = None
  64.  
  65.     
  66.     def errors_occurred(self):
  67.         if not self.failed_dirs and self.mismatched_dirs and self.conflicting_custom_cols:
  68.             pass
  69.         return self.failed_restores
  70.  
  71.     errors_occurred = property(errors_occurred)
  72.     
  73.     def report(self):
  74.         ans = ''
  75.         failures = [] + [ (x['dirpath'], tb) for x, tb in self.failed_restores ]
  76.         if self.conflicting_custom_cols:
  77.             ans += '\n\n'
  78.             ans += 'The following custom columns have conflicting definitions and were not fully restored:\n'
  79.             for x in self.conflicting_custom_cols:
  80.                 ans += '\t#' + x + '\n'
  81.                 ans += '\tused:\t%s, %s, %s, %s\n' % (self.custom_columns[x][1], self.custom_columns[x][2], self.custom_columns[x][3], self.custom_columns[x][5])
  82.                 for coldef in self.conflicting_custom_cols[x]:
  83.                     ans += '\tother:\t%s, %s, %s, %s\n' % (coldef[1], coldef[2], coldef[3], coldef[5])
  84.                 
  85.             
  86.         
  87.         if self.mismatched_dirs:
  88.             ans += '\n\n'
  89.             ans += 'The following folders were ignored:\n'
  90.             for x in self.mismatched_dirs:
  91.                 ans += '\t' + x + '\n'
  92.             
  93.         
  94.         return ans
  95.  
  96.     report = property(report)
  97.     
  98.     def run(self):
  99.         
  100.         try:
  101.             
  102.             try:
  103.                 tdir = _[1]
  104.                 self.library_path = tdir
  105.                 self.scan_library()
  106.                 self.create_cc_metadata()
  107.                 self.restore_books()
  108.                 if self.successes == 0 and len(self.dirs) > 0:
  109.                     raise Exception('Something bad happened')
  110.                 len(self.dirs) > 0
  111.                 self.replace_db()
  112.             finally:
  113.                 pass
  114.  
  115.         except:
  116.             self.tb = traceback.format_exc()
  117.  
  118.  
  119.     
  120.     def scan_library(self):
  121.         for dirpath, dirnames, filenames in os.walk(self.src_library_path):
  122.             leaf = os.path.basename(dirpath)
  123.             m = self.db_id_regexp.search(leaf)
  124.             if m is None or 'metadata.opf' not in filenames:
  125.                 self.ignored_dirs.append(dirpath)
  126.                 continue
  127.             
  128.             self.dirs.append((dirpath, filenames, m.group(1)))
  129.         
  130.         self.progress_callback(None, len(self.dirs))
  131.         for i, x in enumerate(self.dirs):
  132.             (dirpath, filenames, book_id) = x
  133.             
  134.             try:
  135.                 self.process_dir(dirpath, filenames, book_id)
  136.             except:
  137.                 self.failed_dirs.append((dirpath, traceback.format_exc()))
  138.  
  139.             self.progress_callback(_('Processed') + ' ' + dirpath, i + 1)
  140.         
  141.  
  142.     
  143.     def is_ebook_file(self, filename):
  144.         ext = os.path.splitext(filename)[1]
  145.         if not ext:
  146.             return False
  147.         ext = ext[1:].lower()
  148.         if ext in NON_EBOOK_EXTENSIONS or self.bad_ext_pat.search(ext) is not None:
  149.             return False
  150.         return True
  151.  
  152.     
  153.     def process_dir(self, dirpath, filenames, book_id):
  154.         book_id = int(book_id)
  155.         formats = filter(self.is_ebook_file, filenames)
  156.         fmts = [ os.path.splitext(x)[1][1:].upper() for x in formats ]
  157.         sizes = [ os.path.getsize(os.path.join(dirpath, x)) for x in formats ]
  158.         names = [ os.path.splitext(x)[0] for x in formats ]
  159.         opf = os.path.join(dirpath, 'metadata.opf')
  160.         mi = OPF(opf).to_book_metadata()
  161.         timestamp = os.path.getmtime(opf)
  162.         path = os.path.relpath(dirpath, self.src_library_path).replace(os.sep, '/')
  163.  
  164.     
  165.     def create_cc_metadata(self):
  166.         self.books.sort(key = itemgetter('timestamp'))
  167.         self.custom_columns = { }
  168.         fields = ('label', 'name', 'datatype', 'is_multiple', 'is_editable', 'display')
  169.         for b in self.books:
  170.             for key in b['mi'].custom_field_keys():
  171.                 cfm = b['mi'].metadata_for_field(key)
  172.                 args = []
  173.                 for x in fields:
  174.                     if x in cfm:
  175.                         if x == 'is_multiple':
  176.                             args.append(cfm[x] is not None)
  177.                         else:
  178.                             args.append(cfm[x])
  179.                     x == 'is_multiple'
  180.                 
  181.                 if len(args) == len(fields):
  182.                     label = cfm['label']
  183.                     if label in self.custom_columns and args != self.custom_columns[label]:
  184.                         if label not in self.conflicting_custom_cols:
  185.                             self.conflicting_custom_cols[label] = []
  186.                         
  187.                         if self.custom_columns[label] not in self.conflicting_custom_cols[label]:
  188.                             self.conflicting_custom_cols[label].append(self.custom_columns[label])
  189.                         
  190.                     
  191.                     self.custom_columns[label] = args
  192.                     continue
  193.             
  194.         
  195.         db = RestoreDatabase(self.library_path)
  196.         self.progress_callback(None, len(self.custom_columns))
  197.         if len(self.custom_columns):
  198.             for i, args in enumerate(self.custom_columns.values()):
  199.                 db.create_custom_column(*args)
  200.                 self.progress_callback(_('creating custom column ') + args[0], i + 1)
  201.             
  202.         
  203.         db.conn.close()
  204.  
  205.     
  206.     def restore_books(self):
  207.         self.progress_callback(None, len(self.books))
  208.         self.books.sort(key = itemgetter('id'))
  209.         db = RestoreDatabase(self.library_path)
  210.         for i, book in enumerate(self.books):
  211.             
  212.             try:
  213.                 self.restore_book(book, db)
  214.             except:
  215.                 self.failed_restores.append((book, traceback.format_exc()))
  216.  
  217.             self.progress_callback(book['mi'].title, i + 1)
  218.         
  219.         db.conn.close()
  220.  
  221.     
  222.     def restore_book(self, book, db):
  223.         db.create_book_entry(book['mi'], add_duplicates = True, force_id = book['id'])
  224.         if book['mi'].uuid:
  225.             db.set_uuid(book['id'], book['mi'].uuid, commit = False, notify = False)
  226.         
  227.         db.conn.execute('UPDATE books SET path=? WHERE id=?', (book['path'], book['id']))
  228.         for fmt, size, name in book['formats']:
  229.             db.conn.execute('\n                INSERT INTO data (book,format,uncompressed_size,name)\n                VALUES (?,?,?,?)', (book['id'], fmt, size, name))
  230.         
  231.         db.conn.commit()
  232.         self.successes += 1
  233.  
  234.     
  235.     def replace_db(self):
  236.         dbpath = os.path.join(self.src_library_path, 'metadata.db')
  237.         ndbpath = os.path.join(self.library_path, 'metadata.db')
  238.         save_path = self.olddb = os.path.splitext(dbpath)[0] + '_pre_restore.db'
  239.         if os.path.exists(save_path):
  240.             os.remove(save_path)
  241.         
  242.         os.rename(dbpath, save_path)
  243.         shutil.copyfile(ndbpath, dbpath)
  244.  
  245.  
  246.