Pull from trunk

This commit is contained in:
Kovid Goyal 2010-05-15 21:26:06 -06:00
commit ff8bae235b
16 changed files with 195 additions and 38 deletions

View File

@ -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

View File

@ -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'<body.*?<div id="story"', lambda match : '<body><div id="story"'),
(r'<div class="pubdate">.*?</div>', lambda m: ''),
(r'Full HTML version of this story which may include photos, graphics, and related links.*</body>',
@ -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']}) ,
]

View File

@ -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'

View File

@ -1,37 +1,40 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
__copyright__ = '2008 - 2010, Darko Miletic <darko.miletic at gmail.com>'
'''
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
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;} '
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
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')
]
keep_only_tags = [ dict(attrs={'class':['print-title','print-created','print-content','print-links']}) ]
remove_tags = [dict(name='link')]
feeds = [(u"Top Stories", u'http://feedproxy.google.com/TheNationEdPicks')]
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)

View File

@ -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

View File

@ -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):

View File

@ -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:

View File

@ -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'

View File

@ -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]

View File

@ -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:

View File

@ -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)

View File

@ -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',

View File

@ -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
with apply_null_metadata:
save_to_disk(db, task, path, opts, callback)

View File

@ -358,6 +358,7 @@ class FileIconProvider(QFileIconProvider):
'tan' : 'zero',
'epub' : 'epub',
'fb2' : 'fb2',
'rtf' : 'rtf',
}
def __init__(self):

View File

@ -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])

View File

@ -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