Sync to trunk.

This commit is contained in:
John Schember 2009-07-27 19:13:18 -04:00
commit 6ba9ee4bd1
14 changed files with 332 additions and 249 deletions

View File

@ -2,7 +2,7 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
__appname__ = 'calibre' __appname__ = 'calibre'
__version__ = '0.6.1' __version__ = '0.6.2'
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>" __author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
import re import re

View File

@ -199,6 +199,17 @@ class SonyReaderOutput(OutputProfile):
fbase = 12 fbase = 12
fsizes = [7.5, 9, 10, 12, 15.5, 20, 22, 24] fsizes = [7.5, 9, 10, 12, 15.5, 20, 22, 24]
class JetBook5Output(OutputProfile):
name = 'JetBook 5-inch'
short_name = 'jetbook5'
description = _('This profile is intended for the 5-inch JetBook.')
screen_size = (480, 640)
dpi = 168.451
class SonyReaderLandscapeOutput(SonyReaderOutput): class SonyReaderLandscapeOutput(SonyReaderOutput):
name = 'Sony Reader Landscape' name = 'Sony Reader Landscape'
@ -334,4 +345,4 @@ class IRexDR1000Output(OutputProfile):
output_profiles = [OutputProfile, SonyReaderOutput, MSReaderOutput, output_profiles = [OutputProfile, SonyReaderOutput, MSReaderOutput,
MobipocketOutput, HanlinV3Output, CybookG3Output, CybookOpusOutput, MobipocketOutput, HanlinV3Output, CybookG3Output, CybookOpusOutput,
KindleOutput, SonyReaderLandscapeOutput, KindleDXOutput, IlliadOutput, KindleOutput, SonyReaderLandscapeOutput, KindleDXOutput, IlliadOutput,
IRexDR1000Output] IRexDR1000Output, JetBook5Output]

View File

@ -108,11 +108,16 @@ class EPUBOutput(OutputFormatPlugin):
<title>%(title)s</title> <title>%(title)s</title>
<style type="text/css"> <style type="text/css">
body { body {
background: white no-repeat fixed center center;
text-align: center; text-align: center;
vertical-align: center; vertical-align: center;
overflow: hidden; overflow: hidden;
font-size: 18px; font-size: 16pt;
}
.logo {
width: 510px; height: 390px;
text-align:center;
font-size: 1pt;
overflow:hidden;
} }
h1 { font-family: serif; } h1 { font-family: serif; }
h2, h4 { font-family: monospace; } h2, h4 { font-family: monospace; }
@ -120,19 +125,11 @@ class EPUBOutput(OutputFormatPlugin):
</head> </head>
<body> <body>
<h1>%(title)s</h1> <h1>%(title)s</h1>
<br/><br/> <div style="text-align:center">
<div style="position:relative"> <img class="logo" src="%(img)s" alt="calibre logo" />
<div style="position: absolute; left: 0; top: 0; width:100%%; height:100%%; vertical-align:center">
<img src="%(img)s" alt="calibre" style="opacity:0.3"/>
</div> </div>
<div style="position: absolute; left: 0; top: 0; width:100%%; height:100%%; vertical-align:center"> <h2>%(author)s</h2>
<h2>%(date)s</h2>
<br/><br/><br/><br/><br/>
<h3>%(author)s</h3>
<br/><br/><br/><br/><br/><br/><br/><br/><br/>
<h4>Produced by %(app)s</h4> <h4>Produced by %(app)s</h4>
</div>
</div>
</body> </body>
</html> </html>
''' '''
@ -201,7 +198,7 @@ class EPUBOutput(OutputFormatPlugin):
images_rc images_rc
m = self.oeb.metadata m = self.oeb.metadata
title = unicode(m.title[0]) title = unicode(m.title[0])
a = [unicode(x) for x in m.creators if m.role == 'aut'] a = [unicode(x) for x in m.creator if x.role == 'aut']
author = authors_to_string(a) author = authors_to_string(a)
if QApplication.instance() is None: QApplication([]) if QApplication.instance() is None: QApplication([])
f = QFile(':/library') f = QFile(':/library')
@ -211,8 +208,9 @@ class EPUBOutput(OutputFormatPlugin):
'calibre-logo.png') 'calibre-logo.png')
self.oeb.manifest.add(id, href, 'image/png', data=img_data) self.oeb.manifest.add(id, href, 'image/png', data=img_data)
title, author = map(prepare_string_for_xml, (title, author)) title, author = map(prepare_string_for_xml, (title, author))
if not author or not author.strip():
author = strftime('%d %b, %Y')
html = self.TITLEPAGE%dict(title=title, author=author, html = self.TITLEPAGE%dict(title=title, author=author,
date=strftime('%d %b, %Y'),
app=__appname__ +' '+__version__, app=__appname__ +' '+__version__,
img=href) img=href)
id, href = self.oeb.manifest.generate('calibre-titlepage', id, href = self.oeb.manifest.generate('calibre-titlepage',

View File

@ -6,6 +6,16 @@ __docformat__ = 'restructuredtext en'
''' '''
ebook-meta ebook-meta
''' '''
import sys, os
from calibre.utils.config import StringConfig
from calibre.customize.ui import metadata_readers, metadata_writers
from calibre.ebooks.metadata.meta import get_metadata, set_metadata
from calibre.ebooks.metadata import string_to_authors, authors_to_sort_string, \
title_sort, MetaInformation
from calibre.ebooks.lrf.meta import LRFMetaFile
from calibre import prints
USAGE='%%prog ebook_file [' + _('options') + ']\n' + \ USAGE='%%prog ebook_file [' + _('options') + ']\n' + \
_(''' _('''
Read/Write metadata from/to ebook files. Read/Write metadata from/to ebook files.
@ -19,15 +29,7 @@ some metadata on a file type that does not support it, the metadata will be
silently ignored. silently ignored.
''') ''')
import sys, os
from calibre.utils.config import StringConfig
from calibre.customize.ui import metadata_readers, metadata_writers
from calibre.ebooks.metadata.meta import get_metadata, set_metadata
from calibre.ebooks.metadata import string_to_authors, authors_to_sort_string, \
title_sort, MetaInformation
from calibre.ebooks.lrf.meta import LRFMetaFile
from calibre import prints
def config(): def config():
c = StringConfig('') c = StringConfig('')

View File

@ -303,6 +303,11 @@ class MobiReader(object):
self.cleanup_html() self.cleanup_html()
self.log.debug('Parsing HTML...') self.log.debug('Parsing HTML...')
try:
root = html.fromstring(self.processed_html)
except:
self.log.warning('MOBI markup appears to contain random bytes. Stripping.')
self.processed_html = self.remove_random_bytes(self.processed_html)
root = html.fromstring(self.processed_html) root = html.fromstring(self.processed_html)
if root.xpath('descendant::p/descendant::p'): if root.xpath('descendant::p/descendant::p'):
from lxml.html import soupparser from lxml.html import soupparser
@ -444,7 +449,10 @@ class MobiReader(object):
self.processed_html = '<html><p>' + self.processed_html.replace('\n\n', '<p>') + '</html>' self.processed_html = '<html><p>' + self.processed_html.replace('\n\n', '<p>') + '</html>'
self.processed_html = self.processed_html.replace('\r\n', '\n') self.processed_html = self.processed_html.replace('\r\n', '\n')
self.processed_html = self.processed_html.replace('> <', '>\n<') self.processed_html = self.processed_html.replace('> <', '>\n<')
self.processed_html = re.sub('\x14|\x15|\x1c|\x1d|\xef|\x12|\x13|\xec', '', self.processed_html)
def remove_random_bytes(self, html):
return re.sub('\x14|\x15|\x1c|\x1d|\xef|\x12|\x13|\xec',
'', html)
def ensure_unit(self, raw, unit='px'): def ensure_unit(self, raw, unit='px'):
if re.search(r'\d+$', raw) is not None: if re.search(r'\d+$', raw) is not None:

View File

@ -64,4 +64,15 @@ class ODTInput(InputFormatPlugin):
accelerators): accelerators):
return Extract()(stream, '.') return Extract()(stream, '.')
def postprocess_book(self, oeb, opts, log):
# Fix <p><div> constructs as the asinine epubchecker complains
# about them
from calibre.ebooks.oeb.base import XPath, XHTML
path = XPath('//h:p/h:div')
for item in oeb.spine:
root = item.data
if not hasattr(root, 'xpath'): continue
for div in path(root):
div.getparent().tag = XHTML('div')

View File

@ -694,7 +694,6 @@ class Metadata(object):
def to_opf2(self, parent=None): def to_opf2(self, parent=None):
nsmap = self._opf2_nsmap nsmap = self._opf2_nsmap
nsrmap = dict((value, key) for key, value in nsmap.items()) nsrmap = dict((value, key) for key, value in nsmap.items())
nsmap.pop('opf', '')
elem = element(parent, OPF('metadata'), nsmap=nsmap) elem = element(parent, OPF('metadata'), nsmap=nsmap)
for term in self.items: for term in self.items:
for item in self.items[term]: for item in self.items[term]:
@ -815,15 +814,28 @@ class Manifest(object):
data = etree.fromstring(data, parser=RECOVER_PARSER) data = etree.fromstring(data, parser=RECOVER_PARSER)
return data return data
data = first_pass(data) data = first_pass(data)
# Force into the XHTML namespace
# Handle weird (non-HTML/fragment) files
if barename(data.tag) != 'html': if barename(data.tag) != 'html':
self.oeb.log.warn('File %r does not appear to be (X)HTML'%self.href) self.oeb.log.warn('File %r does not appear to be (X)HTML'%self.href)
nroot = etree.fromstring('<html></html>') nroot = etree.fromstring('<html></html>')
has_body = False
for child in list(data):
if barename(child.tag) == 'body':
has_body = True
break
parent = nroot
if not has_body:
self.oeb.log.warn('File %r appears to be a HTML fragment'%self.href)
nroot = etree.fromstring('<html><body/></html>')
parent = nroot[0]
for child in list(data): for child in list(data):
child.getparent().remove(child) child.getparent().remove(child)
nroot.append(child) parent.append(child)
data = nroot data = nroot
elif not namespace(data.tag):
# Force into the XHTML namespace
if not namespace(data.tag):
data.attrib['xmlns'] = XHTML_NS data.attrib['xmlns'] = XHTML_NS
data = etree.tostring(data, encoding=unicode) data = etree.tostring(data, encoding=unicode)
try: try:

View File

@ -3,7 +3,7 @@ __license__ = 'GPL 3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os import os, re
from lxml import etree from lxml import etree
@ -34,6 +34,10 @@ class OEBOutput(OutputFormatPlugin):
if root is not None: if root is not None:
raw = etree.tostring(root, pretty_print=True, raw = etree.tostring(root, pretty_print=True,
encoding='utf-8', xml_declaration=True) encoding='utf-8', xml_declaration=True)
if key == OPF_MIME:
# Needed as I can't get lxml to output opf:role and
# not output <opf:metadata> as well
raw = re.sub(r'(<[/]{0,1})opf:', r'\1', raw)
with open(href, 'wb') as f: with open(href, 'wb') as f:
f.write(raw) f.write(raw)

View File

@ -19,7 +19,7 @@ def meta_info_to_oeb_metadata(mi, m, log):
m.add('title', mi.title_sort) m.add('title', mi.title_sort)
m.title[0].file_as = mi.title_sort m.title[0].file_as = mi.title_sort
if mi.authors: if mi.authors:
m.filter('creator', lambda x : x.role.lower() == 'aut') m.filter('creator', lambda x : x.role.lower() in ['aut', ''])
for a in mi.authors: for a in mi.authors:
attrib = {'role':'aut'} attrib = {'role':'aut'}
if mi.author_sort: if mi.author_sort:

View File

@ -1128,6 +1128,7 @@ class SearchBox(QLineEdit):
self.home(False) self.home(False)
self.initial_state = True self.initial_state = True
self.setStyleSheet("background-color: white") self.setStyleSheet("background-color: white")
self.emit(SIGNAL('cleared()'))
def clear(self): def clear(self):
self.clear_to_help() self.clear_to_help()

View File

@ -456,6 +456,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
SIGNAL('count_changed(int)'), self.location_view.count_changed) SIGNAL('count_changed(int)'), self.location_view.count_changed)
self.connect(self.library_view.model(), SIGNAL('count_changed(int)'), self.connect(self.library_view.model(), SIGNAL('count_changed(int)'),
self.tags_view.recount) self.tags_view.recount)
self.connect(self.search, SIGNAL('cleared()'), self.tags_view.clear)
self.library_view.model().count_changed() self.library_view.model().count_changed()
########################### Cover Flow ################################ ########################### Cover Flow ################################
self.cover_flow = None self.cover_flow = None
@ -1409,7 +1410,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.view_format(row, format) self.view_format(row, format)
break break
if not in_prefs: if not in_prefs:
self.view_format(row, format[0]) self.view_format(row, formats[0])
else: else:
paths = self.current_view().model().paths(rows) paths = self.current_view().model().paths(rows)
for path in paths: for path in paths:

View File

@ -36,6 +36,9 @@ class TagsView(QTreeView):
self.emit(SIGNAL('tags_marked(PyQt_PyObject, PyQt_PyObject)'), self.emit(SIGNAL('tags_marked(PyQt_PyObject, PyQt_PyObject)'),
self._model.tokens(), self.match_all.isChecked()) self._model.tokens(), self.match_all.isChecked())
def clear(self):
self.model().clear_state()
def recount(self, *args): def recount(self, *args):
ci = self.currentIndex() ci = self.currentIndex()
if not ci.isValid(): if not ci.isValid():
@ -119,6 +122,11 @@ class TagsModel(QStandardItemModel):
self._data[category], self.cmap[r], self.bold_font, self.icon_map)) self._data[category], self.cmap[r], self.bold_font, self.icon_map))
#self.reset() #self.reset()
def clear_state(self):
for category in self._data.values():
for tag in category:
tag.state = 0
self.refresh()
def reinit(self, *args, **kwargs): def reinit(self, *args, **kwargs):
if not self.ignore_next_search: if not self.ignore_next_search:

View File

@ -166,6 +166,11 @@ def fetch_scheduled_recipe(recipe, script):
recs.append(('base_font_size', lf['base_font_size'], recs.append(('base_font_size', lf['base_font_size'],
OptionRecommendation.HIGH)) OptionRecommendation.HIGH))
lr = load_defaults('lrf_output')
if lr.get('header', False):
recs.append(('header', True, OptionRecommendation.HIGH))
recs.append(('header_format', '%t', OptionRecommendation.HIGH))
args = [script, pt.name, recs] args = [script, pt.name, recs]
if recipe.needs_subscription: if recipe.needs_subscription:
x = config.get('recipe_account_info_%s'%recipe.id, False) x = config.get('recipe_account_info_%s'%recipe.id, False)

File diff suppressed because it is too large Load Diff