home *** CD-ROM | disk | FTP | other *** search
Wrap
# Source Generated with Decompyle++ # File: in.pyc (Python 2.6) from __future__ import with_statement __license__ = 'GPL 3' __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>' __docformat__ = 'restructuredtext en' import traceback import sys import textwrap import re from threading import Thread from calibre import prints from calibre.utils.config import OptionParser from calibre.utils.logging import default_log from calibre.customize import Plugin from calibre.ebooks.metadata.covers import check_for_cover metadata_config = None class MetadataSource(Plugin): author = 'Kovid Goyal' supported_platforms = [ 'windows', 'osx', 'linux'] metadata_type = 'basic' string_customization_help = None type = _('Metadata download') def __call__(self, title, author, publisher, isbn, verbose, log = None, extra = None): self.worker = Thread(target = self._fetch) self.worker.daemon = True self.title = title self.verbose = verbose self.book_author = author self.publisher = publisher self.isbn = isbn self.log = None if log is not None else default_log self.extra = extra self.exception = None self.tb = None self.results = [] self.worker.start() def _fetch(self): try: self.fetch() if self.results: c = self.config_store().get(self.name, { }) res = self.results if hasattr(res, 'authors'): res = [ res] for mi in res: if not c.get('rating', True): mi.rating = None if not c.get('comments', True): mi.comments = None if not c.get('tags', True): mi.tags = [] continue except Exception: e = None self.exception = e self.tb = traceback.format_exc() def fetch(self): raise NotImplementedError def join(self): return self.worker.join() def is_customizable(self): return True def config_store(self): global metadata_config if metadata_config is None: XMLConfig = XMLConfig import calibre.utils.config metadata_config = XMLConfig('plugins/metadata_download') return metadata_config def config_widget(self): QWidget = QWidget QVBoxLayout = QVBoxLayout QLabel = QLabel Qt = Qt QLineEdit = QLineEdit QCheckBox = QCheckBox import PyQt4.Qt config = config import calibre.customize.ui w = QWidget() w._layout = QVBoxLayout(w) w.setLayout(w._layout) if self.string_customization_help is not None: w._sc_label = QLabel(self.string_customization_help, w) w._layout.addWidget(w._sc_label) customization = config['plugin_customization'] def_sc = customization.get(self.name, '') if not def_sc: def_sc = '' w._sc = QLineEdit(def_sc, w) w._layout.addWidget(w._sc) w._sc_label.setWordWrap(True) w._sc_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard) w._sc_label.setOpenExternalLinks(True) c = self.config_store() c = c.get(self.name, { }) for x, l in { 'rating': _('ratings'), 'tags': _('tags'), 'comments': _('description/reviews') }.items(): cb = QCheckBox(_('Download %s from %s') % (l, self.name)) setattr(w, '_' + x, cb) cb.setChecked(c.get(x, True)) w._layout.addWidget(cb) return w def save_settings(self, w): dl_settings = { } for x in ('rating', 'tags', 'comments'): dl_settings[x] = getattr(w, '_' + x).isChecked() c = self.config_store() c.set(self.name, dl_settings) if hasattr(w, '_sc'): sc = unicode(w._sc.text()).strip() customize_plugin = customize_plugin import calibre.customize.ui customize_plugin(self, sc) def customization_help(self): return 'This plugin can only be customized using the GUI' class GoogleBooks(MetadataSource): name = 'Google Books' description = _('Downloads metadata from Google Books') def fetch(self): search = search import calibre.ebooks.metadata.google_books try: self.results = search(self.title, self.book_author, self.publisher, self.isbn, max_results = 10, verbose = self.verbose) except Exception: e = None self.exception = e self.tb = traceback.format_exc() class ISBNDB(MetadataSource): name = 'IsbnDB' description = _('Downloads metadata from isbndb.com') def fetch(self): if not self.site_customization: return None option_parser = option_parser create_books = create_books import calibre.ebooks.metadata.isbndb args = [ 'isbndb'] if self.isbn: args.extend([ '--isbn', self.isbn]) elif self.title: args.extend([ '--title', self.title]) if self.book_author: args.extend([ '--author', self.book_author]) if self.publisher: args.extend([ '--publisher', self.publisher]) if self.verbose: args.extend([ '--verbose']) args.append(self.site_customization) try: (opts, args) = option_parser().parse_args(args) self.results = create_books(opts, args) except Exception: e = None self.exception = e self.tb = traceback.format_exc() def string_customization_help(self): ans = _('To use isbndb.com you must sign up for a %sfree account%s and enter your access key below.') return '<p>' + ans % ('<a href="http://www.isbndb.com">', '</a>') string_customization_help = property(string_customization_help) class Amazon(MetadataSource): name = 'Amazon' metadata_type = 'social' description = _('Downloads social metadata from amazon.com') def fetch(self): if not self.isbn: return None get_social_metadata = get_social_metadata import calibre.ebooks.metadata.amazon try: self.results = get_social_metadata(self.title, self.book_author, self.publisher, self.isbn) except Exception: self.isbn e = self.isbn self.exception = e self.tb = traceback.format_exc() except: self.isbn class LibraryThing(MetadataSource): name = 'LibraryThing' metadata_type = 'social' description = _('Downloads series/tags/rating information from librarything.com') def fetch(self): if not self.isbn: return None get_social_metadata = get_social_metadata import calibre.ebooks.metadata.library_thing try: self.results = get_social_metadata(self.title, self.book_author, self.publisher, self.isbn) except Exception: self.isbn e = self.isbn self.exception = e self.tb = traceback.format_exc() except: self.isbn def result_index(source, result): if not result.isbn: return -1 for i, x in enumerate(source): if x.isbn == result.isbn: return i return -1 def merge_results(one, two): for x in two: idx = result_index(one, x) if idx < 0: one.append(x) continue one[idx].smart_update(x) class MetadataSources(object): def __init__(self, sources): self.sources = sources def __enter__(self): for s in self.sources: s.__enter__() return self def __exit__(self, *args): for s in self.sources: s.__exit__() def __call__(self, *args, **kwargs): for s in self.sources: s(*args, **kwargs) def join(self): for s in self.sources: s.join() def filter_metadata_results(item): keywords = [ 'audio', 'tape', 'cassette', 'abridged', 'playaway'] for keyword in keywords: if item.publisher and keyword in item.publisher.lower(): return False return True def do_cover_check(item): item.has_cover = False try: item.has_cover = check_for_cover(item) except: pass def check_for_covers(items): threads = [ Thread(target = do_cover_check, args = (item,)) for item in items ] for t in threads: t.start() for t in threads: t.join() def search(title = None, author = None, publisher = None, isbn = None, isbndb_key = None, verbose = 0): metadata_sources = metadata_sources migrate_isbndb_key = migrate_isbndb_key import calibre.customize.ui migrate_isbndb_key() if isbn is not None: isbn = re.sub('[^a-zA-Z0-9]', '', isbn).upper() fetchers = list(metadata_sources(isbndb_key = isbndb_key)) try: manager = _[1] manager(title, author, publisher, isbn, verbose) manager.join() finally: pass results = list(fetchers[0].results) for fetcher in fetchers[1:]: merge_results(results, fetcher.results) results = list(filter(filter_metadata_results, results)) check_for_covers(results) words = ('the', 'a', 'an', 'of', 'and') prefix_pat = re.compile('^(%s)\\s+' % '|'.join(words)) trailing_paren_pat = re.compile('\\(.*\\)$') whitespace_pat = re.compile('\\s+') def sort_func(x, y): def cleanup_title(s): if s is None: s = _('Unknown') s = s.strip().lower() s = prefix_pat.sub(' ', s) s = trailing_paren_pat.sub('', s) s = whitespace_pat.sub(' ', s) return s.strip() t = cleanup_title(title) x_title = cleanup_title(x.title) y_title = cleanup_title(y.title) tx = cmp(t, x_title) ty = cmp(t, y_title) result = (None, None, None) if abs(tx) == abs(ty) else abs(tx) - abs(ty) if result == 0: result = -cmp(x.has_cover, y.has_cover) if result == 0: cx = None(len if x.comments else '') cy = None(len if y.comments else '') t = (cx + cy) / 20 result = cy - cx if abs(result) < t: result = 0 return result results = sorted(results, cmp = sort_func) if len(results) > 1: if not (results[0].comments) or len(results[0].comments) == 0: for r in results[1:]: try: if title and title.lower() == r.title[:len(title)].lower() and r.comments and len(r.comments): results[0].comments = r.comments break continue continue pubdate = None for r in results: if r.pubdate is not None: pubdate = r.pubdate break continue if pubdate is not None: for r in results: if r.pubdate is None: r.pubdate = pubdate continue return ([], [ (x.name, x.exception, x.tb) for x in fetchers ]) def get_social_metadata(mi, verbose = 0): metadata_sources = metadata_sources import calibre.customize.ui fetchers = list(metadata_sources(metadata_type = 'social')) try: manager = _[1] manager(mi.title, mi.authors, mi.publisher, mi.isbn, verbose) manager.join() finally: pass (ratings, tags, comments, series, series_index) = ([], set([]), set([]), None, None) for fetcher in fetchers: if fetcher.results: dmi = fetcher.results if dmi.tags: for t in dmi.tags: tags.add(t) if mi.pubdate is None and dmi.pubdate is not None: mi.pubdate = dmi.pubdate if dmi.comments: comments.add(dmi.comments) if dmi.series is not None: series = dmi.series if dmi.series_index is not None: series_index = dmi.series_index dmi.series is not None if ratings: rating = sum(ratings) / float(len(ratings)) if mi.rating is None or mi.rating < 0.1: mi.rating = rating else: mi.rating = (mi.rating + rating) / 2 if tags: if not mi.tags: mi.tags = [] mi.tags += list(tags) mi.tags = list(sorted(list(set(mi.tags)))) if comments: if not (mi.comments) or len(mi.comments) + 20 < len(' '.join(comments)): mi.comments = '' for x in comments: mi.comments += x + '\n\n' if series and series_index is not None: mi.series = series mi.series_index = series_index return _[2] def option_parser(): parser = OptionParser(textwrap.dedent(' %prog [options]\n\n Fetch book metadata from online sources. You must specify at least one\n of title, author, publisher or ISBN. If you specify ISBN, the others\n are ignored.\n ')) parser.add_option('-t', '--title', help = 'Book title') parser.add_option('-a', '--author', help = 'Book author(s)') parser.add_option('-p', '--publisher', help = 'Book publisher') parser.add_option('-i', '--isbn', help = 'Book ISBN') parser.add_option('-m', '--max-results', default = 10, help = 'Maximum number of results to fetch') parser.add_option('-k', '--isbndb-key', help = "The access key for your ISBNDB.com account. Only needed if you want to search isbndb.com and you haven't customized the IsbnDB plugin.") parser.add_option('-v', '--verbose', default = 0, action = 'count', help = 'Be more verbose about errors') return parser def main(args = sys.argv): parser = option_parser() (opts, args) = parser.parse_args(args) (results, exceptions) = search(opts.title, opts.author, opts.publisher, opts.isbn, opts.isbndb_key, opts.verbose) social_exceptions = [] for result in results: social_exceptions.extend(get_social_metadata(result, opts.verbose)) prints(unicode(result)) print for name, exception, tb in exceptions + social_exceptions: if exception is not None: print 'WARNING: Fetching from', name, 'failed with error:' print exception print tb continue return 0 if __name__ == '__main__': sys.exit(main())