From a96002fa1bc9580ebc9323cb1c9fdfa745a34693 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 15 May 2010 09:24:19 -0600 Subject: [PATCH 01/11] Fix #5525 ("The Nation" recipe not working) --- resources/recipes/the_nation.recipe | 51 +++++++++++++++-------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/resources/recipes/the_nation.recipe b/resources/recipes/the_nation.recipe index 2a1f226e56..0e4d8d83ef 100644 --- a/resources/recipes/the_nation.recipe +++ b/resources/recipes/the_nation.recipe @@ -1,37 +1,40 @@ -#!/usr/bin/env python - __license__ = 'GPL v3' -__copyright__ = '2008, Darko Miletic ' +__copyright__ = '2008 - 2010, Darko Miletic ' ''' thenation.com ''' from calibre.web.feeds.news import BasicNewsRecipe class Thenation(BasicNewsRecipe): - title = u'The Nation' - __author__ = u'Darko Miletic' - description = u'Unconventional Wisdom Since 1865' + title = 'The Nation' + __author__ = 'Darko Miletic' + description = 'Unconventional Wisdom Since 1865' + publisher = 'The Nation' + category = 'news, politics, USA' oldest_article = 120 + encoding = 'utf-8' max_articles_per_feed = 100 no_stylesheets = True - language = 'en' - - use_embedded_content = False - simultaneous_downloads = 1 + language = 'en' + use_embedded_content = False delay = 1 - timefmt = ' [%A, %d %B, %Y]' - + masthead_url = 'http://www.thenation.com/sites/default/themes/thenation/images/logo-main.gif' + exra_css = ' body{font-family: Arial,Helvetica,sans-serif;} .print-created{font-size: small;} .caption{display: block; font-size: x-small;} ' - keep_only_tags = [ dict(name='div', attrs={'class':'main'}) ] - remove_tags = [ - dict(name='div', attrs={'class':'mod tools'}) - ,dict(name='div', attrs={'class':'inset' }) - ,dict(name='div', attrs={'class':'share' }) - ,dict(name='ol' , attrs={'id' :'comments' }) - ,dict(name='p' , attrs={'class':'info' }) - ,dict(name='a' , attrs={'class':'comments' }) - ,dict(name='ul' , attrs={'class':'important'}) - ,dict(name='object') - ] + conversion_options = { + 'comment' : description + , 'tags' : category + , 'publisher' : publisher + , 'language' : language + } - feeds = [(u"Top Stories", u'http://feedproxy.google.com/TheNationEdPicks')] + keep_only_tags = [ dict(attrs={'class':['print-title','print-created','print-content','print-links']}) ] + remove_tags = [dict(name='link')] + + feeds = [(u"Editor's Picks", u'http://www.thenation.com/rss/editors_picks')] + + def print_version(self, url): + return url.replace('.thenation.com/','.thenation.com/print/') + + def preprocess_html(self, soup): + return self.adeify_images(soup) From b7421bc3caf42e88125d31365cefc37e277dff98 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 15 May 2010 09:55:29 -0600 Subject: [PATCH 02/11] ... --- src/calibre/devices/hanvon/driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/devices/hanvon/driver.py b/src/calibre/devices/hanvon/driver.py index 463dc69079..aa384910cd 100644 --- a/src/calibre/devices/hanvon/driver.py +++ b/src/calibre/devices/hanvon/driver.py @@ -24,7 +24,7 @@ class N516(USBMS): VENDOR_ID = [0x0525] PRODUCT_ID = [0xa4a5] - BCD = [0x323, 0x326] + BCD = [0x323, 0x326, 0x399] VENDOR_NAME = 'INGENIC' WINDOWS_MAIN_MEM = '_FILE-STOR_GADGE' From de305d2d950f6ffc088bb9f2b26e9299045fb604 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 15 May 2010 10:14:29 -0600 Subject: [PATCH 03/11] EPUB Input: Fix typo that caused incorrect processing of EPUB files with more than one identifier element and encrypted fonts --- src/calibre/ebooks/epub/input.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/calibre/ebooks/epub/input.py b/src/calibre/ebooks/epub/input.py index 48699521c7..0f94fb674a 100644 --- a/src/calibre/ebooks/epub/input.py +++ b/src/calibre/ebooks/epub/input.py @@ -32,9 +32,9 @@ class EPUBInput(InputFormatPlugin): key = None for item in opf.identifier_iter(): scheme = None - for key in item.attrib.keys(): - if key.endswith('scheme'): - scheme = item.get(key) + for xkey in item.attrib.keys(): + if xkey.endswith('scheme'): + scheme = item.get(xkey) if (scheme and scheme.lower() == 'uuid') or \ (item.text and item.text.startswith('urn:uuid:')): key = str(item.text).rpartition(':')[-1] From d866fcc48f076c3f9c639b68d114015507059e16 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 15 May 2010 10:29:21 -0600 Subject: [PATCH 04/11] Fix #5501 (Error after query of social metadata if ISBN not find) --- src/calibre/ebooks/metadata/amazon.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/calibre/ebooks/metadata/amazon.py b/src/calibre/ebooks/metadata/amazon.py index d1473be8f0..1713d044f5 100644 --- a/src/calibre/ebooks/metadata/amazon.py +++ b/src/calibre/ebooks/metadata/amazon.py @@ -19,12 +19,18 @@ AWS_NS = 'http://webservices.amazon.com/AWSECommerceService/2005-10-05' def AWS(tag): return '{%s}%s'%(AWS_NS, tag) -def check_for_errors(root): +class ISBNNotFound(ValueError): + pass + +def check_for_errors(root, isbn): err = root.find('.//'+AWS('Error')) if err is not None: + text = etree.tostring(err, method='text', pretty_print=True, + encoding=unicode) + if 'AWS.InvalidParameterValue'+isbn in text: + raise ISBNNotFound(isbn) raise Exception('Failed to get metadata with error: '\ - + etree.tostring(err, method='text', pretty_print=True, - encoding=unicode)) + + text) def get_social_metadata(title, authors, publisher, isbn): mi = MetaInformation(title, authors) @@ -32,7 +38,10 @@ def get_social_metadata(title, authors, publisher, isbn): br = browser() response_xml = br.open('http://status.calibre-ebook.com/aws/metadata/'+isbn).read() root = etree.fromstring(response_xml) - check_for_errors(root) + try: + check_for_errors(root, isbn) + except ISBNNotFound: + return mi mi.title = root.findtext('.//'+AWS('Title')) authors = [x.text for x in root.findall('.//'+AWS('Author'))] if authors: From b8af81da1077d1cb08239a10bd4daecc4f0a2d58 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 15 May 2010 10:54:10 -0600 Subject: [PATCH 05/11] Improve the Christian Science Monitor --- resources/recipes/chr_mon.recipe | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/resources/recipes/chr_mon.recipe b/resources/recipes/chr_mon.recipe index 79c991efa8..2b431ebd0b 100644 --- a/resources/recipes/chr_mon.recipe +++ b/resources/recipes/chr_mon.recipe @@ -37,6 +37,7 @@ class ChristianScienceMonitor(BasicNewsRecipe): preprocess_regexps = [ (re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in [ + (r'', lambda match : ''), (r'
.*?
', lambda m: ''), (r'Full HTML version of this story which may include photos, graphics, and related links.*', @@ -79,7 +80,10 @@ class ChristianScienceMonitor(BasicNewsRecipe): remove_tags = [ dict(name='div', attrs={'id':['story-tools','videoPlayer','storyRelatedBottom','enlarge-photo','photo-paginate']}), - dict(name='div', attrs={'class':['storyToolbar cfx','podStoryRel','spacer3','divvy spacer7','comment','storyIncludeBottom']}), + dict(name=['div','a'], attrs={'class': + ['storyToolbar cfx','podStoryRel','spacer3', + 'divvy spacer7','comment','storyIncludeBottom', + 'hide', 'podBrdr']}), dict(name='ul', attrs={'class':[ 'centerliststories']}) , dict(name='form', attrs={'id':[ 'commentform']}) , ] From 421475f02a696d2fb1cd07d399d74e64becda777 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 15 May 2010 10:58:00 -0600 Subject: [PATCH 06/11] Fix #5503 (Add an icon for the RTF file format) --- src/calibre/gui2/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 94f969d7e9..4c75758567 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -339,6 +339,7 @@ class FileIconProvider(QFileIconProvider): 'tan' : 'zero', 'epub' : 'epub', 'fb2' : 'fb2', + 'rtf' : 'rtf', } def __init__(self): From 56e2918c1311f02647a2ddc2a38f1edbab2268b5 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 15 May 2010 12:24:10 -0600 Subject: [PATCH 07/11] calibredb: Add ability to create empty books in the database. Fixes #5504 (Improve bulk creation of empty book items) --- src/calibre/library/cli.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/calibre/library/cli.py b/src/calibre/library/cli.py index 7f2c4ab926..12b7944383 100644 --- a/src/calibre/library/cli.py +++ b/src/calibre/library/cli.py @@ -376,12 +376,35 @@ the directory related options below. help=_('Process directories recursively')) parser.add_option('-d', '--duplicates', action='store_true', default=False, help=_('Add books to database even if they already exist. Comparison is done based on book titles.')) + parser.add_option('-e', '--empty', action='store_true', default=False, + help=_('Add an empty book (a book with no formats)')) + parser.add_option('-t', '--title', default=None, + help=_('Set the title of the added empty book')) + parser.add_option('-a', '--authors', default=None, + help=_('Set the authors of the added empty book')) + parser.add_option('-i', '--isbn', default=None, + help=_('Set the ISBN of the added empty book')) + return parser +def do_add_empty(db, title, authors, isbn): + from calibre.ebooks.metadata import MetaInformation, string_to_authors + mi = MetaInformation(None) + if title is not None: + mi.title = title + if authors: + mi.authors = string_to_authors(authors) + if isbn: + mi.isbn = isbn + db.import_book(mi, []) + send_message() def command_add(args, dbpath): parser = add_option_parser() opts, args = parser.parse_args(sys.argv[:1] + args) + if opts.empty: + do_add_empty(get_db(dbpath, opts), opts.title, opts.authors, opts.isbn) + return 0 if len(args) < 2: parser.print_help() print From eabd4dc9b57f23e7c5b1f9971ba23dfc410c27a8 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 15 May 2010 19:18:36 -0600 Subject: [PATCH 08/11] ... --- resources/recipes/the_escapist.recipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/recipes/the_escapist.recipe b/resources/recipes/the_escapist.recipe index 6ff8debe53..5730dd2858 100644 --- a/resources/recipes/the_escapist.recipe +++ b/resources/recipes/the_escapist.recipe @@ -15,7 +15,7 @@ class al(BasicNewsRecipe): description = 'The Escapist Magazine' cover_url = 'http://cdn.themis-media.com/themes/escapistmagazine/default/images/logo.png' - title = u'the Escapist Magazine' + title = u'The Escapist Magazine' publisher = 'Themis media' category = 'Video games news, lifestyle, gaming culture' From d7a9c4884941340384736e92785eeeffa1eec01f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 15 May 2010 19:32:52 -0600 Subject: [PATCH 09/11] Fix #5500 (adding duplicate books creates temporary blank line at bottom of book list) --- src/calibre/gui2/add.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/add.py b/src/calibre/gui2/add.py index 3f9d1925b5..becf78e85f 100644 --- a/src/calibre/gui2/add.py +++ b/src/calibre/gui2/add.py @@ -199,11 +199,11 @@ class DBAdder(Thread): self.add_formats(id, formats) else: id = self.db.create_book_entry(mi, cover=cover, add_duplicates=False) - self.number_of_books_added += 1 if id is None: self.duplicates.append((mi, cover, orig_formats)) else: self.add_formats(id, formats) + self.number_of_books_added += 1 else: self.names.append(name) self.paths.append(formats[0]) From 561f7a2c68c179cbde915962953a33bd715caacc Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 15 May 2010 20:43:21 -0600 Subject: [PATCH 10/11] Fix #5518 (EPUB: Unable to clear or delete series and update file series meta data when saving to disk) --- src/calibre/customize/__init__.py | 4 ++++ src/calibre/customize/builtins.py | 2 +- src/calibre/customize/ui.py | 13 +++++++++++++ src/calibre/ebooks/metadata/epub.py | 10 +++++++++- src/calibre/ebooks/metadata/opf2.py | 9 +++++++++ src/calibre/ebooks/metadata/worker.py | 4 +++- 6 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/calibre/customize/__init__.py b/src/calibre/customize/__init__.py index 0d6f041736..4eaaf3b90a 100644 --- a/src/calibre/customize/__init__.py +++ b/src/calibre/customize/__init__.py @@ -236,6 +236,10 @@ class MetadataWriterPlugin(Plugin): type = _('Metadata writer') + def __init__(self, *args, **kwargs): + Plugin.__init__(self, *args, **kwargs) + self.apply_null = False + def set_metadata(self, stream, mi, type): ''' Set metadata for the file represented by stream (a file like object diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index e9dd3d0cb4..52ec8fa255 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -329,7 +329,7 @@ class EPUBMetadataWriter(MetadataWriterPlugin): def set_metadata(self, stream, mi, type): from calibre.ebooks.metadata.epub import set_metadata - set_metadata(stream, mi) + set_metadata(stream, mi, apply_null=self.apply_null) class LRFMetadataWriter(MetadataWriterPlugin): diff --git a/src/calibre/customize/ui.py b/src/calibre/customize/ui.py index 68c26386c9..a2521b0023 100644 --- a/src/calibre/customize/ui.py +++ b/src/calibre/customize/ui.py @@ -187,6 +187,18 @@ class QuickMetadata(object): quick_metadata = QuickMetadata() +class ApplyNullMetadata(object): + + def __init__(self): + self.apply_null = False + + def __enter__(self): + self.apply_null = True + + def __exit__(self, *args): + self.apply_null = False + +apply_null_metadata = ApplyNullMetadata() def get_file_type_metadata(stream, ftype): mi = MetaInformation(None, None) @@ -214,6 +226,7 @@ def set_file_type_metadata(stream, mi, ftype): if not is_disabled(plugin): with plugin: try: + plugin.apply_null = apply_null_metadata.apply_null plugin.set_metadata(stream, mi, ftype.lower().strip()) break except: diff --git a/src/calibre/ebooks/metadata/epub.py b/src/calibre/ebooks/metadata/epub.py index 1dab9cd91c..d74ed37f66 100644 --- a/src/calibre/ebooks/metadata/epub.py +++ b/src/calibre/ebooks/metadata/epub.py @@ -182,13 +182,21 @@ def get_metadata(stream, extract_cover=True): def get_quick_metadata(stream): return get_metadata(stream, False) -def set_metadata(stream, mi): +def set_metadata(stream, mi, apply_null=False): stream.seek(0) reader = OCFZipReader(stream, root=os.getcwdu()) mi = MetaInformation(mi) for x in ('guide', 'toc', 'manifest', 'spine'): setattr(mi, x, None) reader.opf.smart_update(mi) + if apply_null: + if not getattr(mi, 'series', None): + reader.opf.series = None + if not getattr(mi, 'tags', []): + reader.opf.tags = [] + if not getattr(mi, 'isbn', None): + reader.opf.isbn = None + newopf = StringIO(reader.opf.render()) safe_replace(stream, reader.container[OPF.MIMETYPE], newopf) diff --git a/src/calibre/ebooks/metadata/opf2.py b/src/calibre/ebooks/metadata/opf2.py index 7eeac5cc85..e429574e57 100644 --- a/src/calibre/ebooks/metadata/opf2.py +++ b/src/calibre/ebooks/metadata/opf2.py @@ -404,6 +404,10 @@ class MetadataField(object): def __set__(self, obj, val): elem = obj.get_metadata_element(self.name) + if val is None: + if elem is not None: + elem.getparent().remove(elem) + return if elem is None: elem = obj.create_metadata_element(self.name, is_dc=self.is_dc) obj.set_text(elem, unicode(val)) @@ -722,6 +726,11 @@ class OPF(object): def fset(self, val): matches = self.isbn_path(self.metadata) + if val is None: + if matches: + for x in matches: + x.getparent().remove(x) + return if not matches: attrib = {'{%s}scheme'%self.NAMESPACES['opf']: 'ISBN'} matches = [self.create_metadata_element('identifier', diff --git a/src/calibre/ebooks/metadata/worker.py b/src/calibre/ebooks/metadata/worker.py index 3fc33f42cd..178174a0d7 100644 --- a/src/calibre/ebooks/metadata/worker.py +++ b/src/calibre/ebooks/metadata/worker.py @@ -235,6 +235,7 @@ def save_book(task, library_path, path, recs, notification=lambda x,y:x): from calibre.library.database2 import LibraryDatabase2 db = LibraryDatabase2(library_path) from calibre.library.save_to_disk import config, save_to_disk + from calibre.customize.ui import apply_null_metadata opts = config().parse() for name in recs: setattr(opts, name, recs[name]) @@ -244,5 +245,6 @@ def save_book(task, library_path, path, recs, notification=lambda x,y:x): notification((id, title, not failed, tb)) return True - save_to_disk(db, task, path, opts, callback) + with apply_null_metadata: + save_to_disk(db, task, path, opts, callback) From 70f94c6b71c25230d44e239c54fdeb17e6798daf Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 15 May 2010 21:24:56 -0600 Subject: [PATCH 11/11] version 0.6.53 --- Changelog.yaml | 81 ++++++++++++++++++++++++++++++++++++++++ src/calibre/constants.py | 2 +- 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/Changelog.yaml b/Changelog.yaml index ec083af809..d6204743f8 100644 --- a/Changelog.yaml +++ b/Changelog.yaml @@ -4,6 +4,87 @@ # for important features/bug fixes. # Also, each release can have new and improved recipes. +- version: 0.6.53 + date: 2010-05-15 + + new features: + - title: "Clean up GUI initialization and add support for restoring corrupted databases automatically" + + - title: "Make proxy detection more robust on windows and OS X. calibre now queries OS X Network Settigns if no environment variables are set. Also handle proxies with a trailing slash correctly" + + - title: "Add EPUB advanced formatting demo to User Manual" + + - title: "Support for the Booq Avant, Azbooka and the Samsung GT-I5700" + + - title: "Backwards search in the E-book viewer" + + - title: "calibredb: Add ability to create empty books in the database." + tickets: [5504] + + - title: "Conversion pipeline: Support for the :first-letter pseudo selector" + + - title: "Interpret a Keyboard interrupt (Ctrl+C) as a request to quit the main GUI" + + - title: "CBC Input: Handle comics.txt encoded in UTF-16 with a BOM" + + bug fixes: + - title: "HTML Input: Fix silly bug in case sensitivity detection" + + - title: "Kobo driver: Show all sideloaded content on the device." + tickets: [5492] + + - title: "EPUB metadata: Fix bug with relative apths in encryption detection when reading cover" + tickets: [5471] + + - title: "E-book viewer: Fix next page scrolling when current document is just a little more than a screenfull. Also use a more robust method to insert blank space at the end of the document when the last screenfull is partially empty." + + - title: "EPUB metadata: Allow deletion of series/tags/isbn from EPUB files when Saving to Disk" + tickets: [5518] + + - title: "Fix regression that caused temporary blank line at the bottom of the books list when adding duplicates" + tickets: [5500] + + - title: "Add icon for RTF" + tickets: [5503] + + - title: "Amazon metadata: If ISBN is not found, don't report an error message." + tickets: [5501] + + - title: "EPUB Input: Fix typo that caused incorrect processing of EPUB files with more than one identifier element and encrypted fonts" + + - title: "Fix bug that caused send to device to send multiple copies to the device if you had previously used Prefrences" + + - title: "Linux prs 500 udev rule: Use SUBSYSTEMS instead of the deprecated BUS" + + - title: "PML2PMLZ plugin: Actually compress the PML file stored in the PMLZ archive" + tickets: [5511] + + - title: "SONY drivers: Fix regression that broke collection ordering by series when sending to device. And fix another rare error condition." + tickets: [5487] + + - title: "CHM Input: Regression that broke CHM conversion on OS X." + tickets: [5483] + + - title: "Fix PDB created in Dropbook not convertable by Calibre" + tickets: [5441] + + + new recipes: + - title: APCOM, Leggo (it), Ansa and Punto Informatico + author: Gabriele Marini + + - title: Scinexx.de + author: JSuer + + - title: Various Russian news sources + author: Darko Miletic + + improved recipes: + - Christian Science Monitor + - The Nation + - Physics World + - Discover Magazine + - version: 0.6.52 date: 2010-05-07 diff --git a/src/calibre/constants.py b/src/calibre/constants.py index b470b3c239..7e52798e65 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -2,7 +2,7 @@ __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __docformat__ = 'restructuredtext en' __appname__ = 'calibre' -__version__ = '0.6.52' +__version__ = '0.6.53' __author__ = "Kovid Goyal " import re