home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_952 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  10.5 KB  |  297 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. from __future__ import with_statement
  5. __license__ = 'GPL 3'
  6. __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>; 2010, Li Fanxi <lifanxi@freemindworld.com>'
  7. __docformat__ = 'restructuredtext en'
  8. import sys
  9. import textwrap
  10. import traceback
  11. from urllib import urlencode
  12. from functools import partial
  13. from lxml import etree
  14. from calibre import browser, preferred_encoding
  15. from calibre.ebooks.metadata import MetaInformation
  16. from calibre.utils.config import OptionParser
  17. from calibre.ebooks.metadata.fetch import MetadataSource
  18. from calibre.utils.date import parse_date, utcnow
  19. NAMESPACES = {
  20.     'openSearch': 'http://a9.com/-/spec/opensearchrss/1.0/',
  21.     'atom': 'http://www.w3.org/2005/Atom',
  22.     'db': 'http://www.douban.com/xmlns/' }
  23. XPath = partial(etree.XPath, namespaces = NAMESPACES)
  24. total_results = XPath('//openSearch:totalResults')
  25. start_index = XPath('//openSearch:startIndex')
  26. items_per_page = XPath('//openSearch:itemsPerPage')
  27. entry = XPath('//atom:entry')
  28. entry_id = XPath('descendant::atom:id')
  29. title = XPath('descendant::atom:title')
  30. description = XPath('descendant::atom:summary')
  31. publisher = XPath("descendant::db:attribute[@name='publisher']")
  32. isbn = XPath("descendant::db:attribute[@name='isbn13']")
  33. date = XPath("descendant::db:attribute[@name='pubdate']")
  34. creator = XPath("descendant::db:attribute[@name='author']")
  35. tag = XPath('descendant::db:tag')
  36. CALIBRE_DOUBAN_API_KEY = '0bd1672394eb1ebf2374356abec15c3d'
  37.  
  38. class DoubanBooks(MetadataSource):
  39.     name = 'Douban Books'
  40.     description = _('Downloads metadata from Douban.com')
  41.     supported_platforms = [
  42.         'windows',
  43.         'osx',
  44.         'linux']
  45.     author = 'Li Fanxi <lifanxi@freemindworld.com>'
  46.     version = (1, 0, 1)
  47.     
  48.     def fetch(self):
  49.         
  50.         try:
  51.             self.results = search(self.title, self.book_author, self.publisher, self.isbn, max_results = 10, verbose = self.verbose)
  52.         except Exception:
  53.             e = None
  54.             self.exception = e
  55.             self.tb = traceback.format_exc()
  56.  
  57.  
  58.  
  59.  
  60. def report(verbose):
  61.     if verbose:
  62.         import traceback
  63.         traceback.print_exc()
  64.     
  65.  
  66.  
  67. class Query(object):
  68.     SEARCH_URL = 'http://api.douban.com/book/subjects?'
  69.     ISBN_URL = 'http://api.douban.com/book/subject/isbn/'
  70.     type = 'search'
  71.     
  72.     def __init__(self, title = None, author = None, publisher = None, isbn = None, max_results = 20, start_index = 1, api_key = ''):
  73.         q = ''
  74.         if isbn is not None:
  75.             q = isbn
  76.             self.type = 'isbn'
  77.         else:
  78.             
  79.             def build_term(parts):
  80.                 return ' '.join((lambda .0: for x in .0:
  81. x)(parts))
  82.  
  83.             if title is not None:
  84.                 q += build_term(title.split())
  85.             
  86.             if author is not None:
  87.                 None += q if q else '' + build_term(author.split())
  88.             
  89.             if publisher is not None:
  90.                 None += q if q else '' + build_term(publisher.split())
  91.             
  92.             self.type = 'search'
  93.         if isinstance(q, unicode):
  94.             q = q.encode('utf-8')
  95.         
  96.         if self.type == 'isbn':
  97.             self.url = self.ISBN_URL + q
  98.             if api_key != '':
  99.                 self.url = self.url + '?apikey=' + api_key
  100.             
  101.         else:
  102.             self.url = self.SEARCH_URL + urlencode({
  103.                 'q': q,
  104.                 'max-results': max_results,
  105.                 'start-index': start_index })
  106.             if api_key != '':
  107.                 self.url = self.url + '&apikey=' + api_key
  108.             
  109.  
  110.     
  111.     def __call__(self, browser, verbose):
  112.         if verbose:
  113.             print 'Query:', self.url
  114.         
  115.         if self.type == 'search':
  116.             feed = etree.fromstring(browser.open(self.url).read())
  117.             total = int(total_results(feed)[0].text)
  118.             start = int(start_index(feed)[0].text)
  119.             entries = entry(feed)
  120.             new_start = start + len(entries)
  121.             if new_start > total:
  122.                 new_start = 0
  123.             
  124.             return (entries, new_start)
  125.         if self.type == 'isbn':
  126.             feed = etree.fromstring(browser.open(self.url).read())
  127.             entries = entry(feed)
  128.             return (entries, 0)
  129.  
  130.  
  131.  
  132. class ResultList(list):
  133.     
  134.     def get_description(self, entry, verbose):
  135.         
  136.         try:
  137.             desc = description(entry)
  138.             if desc:
  139.                 return 'SUMMARY:\n' + desc[0].text
  140.         except:
  141.             report(verbose)
  142.  
  143.  
  144.     
  145.     def get_title(self, entry):
  146.         candidates = [ x.text for x in title(entry) ]
  147.         return ': '.join(candidates)
  148.  
  149.     
  150.     def get_authors(self, entry):
  151.         m = creator(entry)
  152.         if not m:
  153.             m = []
  154.         
  155.         m = [ x.text for x in m ]
  156.         return m
  157.  
  158.     
  159.     def get_tags(self, entry, verbose):
  160.         
  161.         try:
  162.             btags = [ x.attrib['name'] for x in tag(entry) ]
  163.             tags = []
  164.             for t in btags:
  165.                 []([ y.strip() for y in t.split('/') ])
  166.             
  167.             tags = list(sorted(list(set(tags))))
  168.         except:
  169.             report(verbose)
  170.             tags = []
  171.  
  172.         return [ x.replace(',', ';') for x in tags ]
  173.  
  174.     
  175.     def get_publisher(self, entry, verbose):
  176.         
  177.         try:
  178.             pub = publisher(entry)[0].text
  179.         except:
  180.             pub = None
  181.  
  182.         return pub
  183.  
  184.     
  185.     def get_isbn(self, entry, verbose):
  186.         
  187.         try:
  188.             isbn13 = isbn(entry)[0].text
  189.         except Exception:
  190.             isbn13 = None
  191.  
  192.         return isbn13
  193.  
  194.     
  195.     def get_date(self, entry, verbose):
  196.         
  197.         try:
  198.             d = date(entry)
  199.             if d:
  200.                 default = utcnow().replace(day = 15)
  201.                 d = parse_date(d[0].text, assume_utc = True, default = default)
  202.             else:
  203.                 d = None
  204.         except:
  205.             report(verbose)
  206.             d = None
  207.  
  208.         return d
  209.  
  210.     
  211.     def populate(self, entries, browser, verbose = False, api_key = ''):
  212.         for x in entries:
  213.             
  214.             try:
  215.                 id_url = entry_id(x)[0].text
  216.                 title = self.get_title(x)
  217.             except:
  218.                 report(verbose)
  219.  
  220.             mi = MetaInformation(title, self.get_authors(x))
  221.             
  222.             try:
  223.                 if api_key != '':
  224.                     id_url = id_url + '?apikey=' + api_key
  225.                 
  226.                 raw = browser.open(id_url).read()
  227.                 feed = etree.fromstring(raw)
  228.                 x = entry(feed)[0]
  229.             except Exception:
  230.                 e = None
  231.                 if verbose:
  232.                     print 'Failed to get all details for an entry'
  233.                     print e
  234.                 
  235.             except:
  236.                 verbose
  237.  
  238.             mi.comments = self.get_description(x, verbose)
  239.             mi.tags = self.get_tags(x, verbose)
  240.             mi.isbn = self.get_isbn(x, verbose)
  241.             mi.publisher = self.get_publisher(x, verbose)
  242.             mi.pubdate = self.get_date(x, verbose)
  243.             self.append(mi)
  244.         
  245.  
  246.  
  247.  
  248. def search(title = None, author = None, publisher = None, isbn = None, verbose = False, max_results = 40, api_key = None):
  249.     br = browser()
  250.     start = 1
  251.     entries = []
  252.     if api_key is None:
  253.         api_key = CALIBRE_DOUBAN_API_KEY
  254.     
  255.     while start > 0 and len(entries) <= max_results:
  256.         (new, start) = Query(title = title, author = author, publisher = publisher, isbn = isbn, max_results = max_results, start_index = start, api_key = api_key)(br, verbose)
  257.         if not new:
  258.             break
  259.         
  260.         entries.extend(new)
  261.     entries = entries[:max_results]
  262.     ans = ResultList()
  263.     ans.populate(entries, br, verbose, api_key)
  264.     return ans
  265.  
  266.  
  267. def option_parser():
  268.     parser = OptionParser(textwrap.dedent('        %prog [options]\n\n        Fetch book metadata from Douban. You must specify one of title, author,\n        publisher or ISBN. If you specify ISBN the others are ignored. Will\n        fetch a maximum of 100 matches, so you should make your query as\n        specific as possible.\n        '))
  269.     parser.add_option('-t', '--title', help = 'Book title')
  270.     parser.add_option('-a', '--author', help = 'Book author(s)')
  271.     parser.add_option('-p', '--publisher', help = 'Book publisher')
  272.     parser.add_option('-i', '--isbn', help = 'Book ISBN')
  273.     parser.add_option('-m', '--max-results', default = 10, help = 'Maximum number of results to fetch')
  274.     parser.add_option('-v', '--verbose', default = 0, action = 'count', help = 'Be more verbose about errors')
  275.     return parser
  276.  
  277.  
  278. def main(args = sys.argv):
  279.     parser = option_parser()
  280.     (opts, args) = parser.parse_args(args)
  281.     
  282.     try:
  283.         results = search(opts.title, opts.author, opts.publisher, opts.isbn, verbose = opts.verbose, max_results = int(opts.max_results))
  284.     except AssertionError:
  285.         report(True)
  286.         parser.print_help()
  287.         return 1
  288.  
  289.     for result in results:
  290.         print unicode(result).encode(preferred_encoding)
  291.         print 
  292.     
  293.  
  294. if __name__ == '__main__':
  295.     sys.exit(main())
  296.  
  297.