diff --git a/src/calibre/__init__.py b/src/calibre/__init__.py
index acd5d2e930..5c55632da9 100644
--- a/src/calibre/__init__.py
+++ b/src/calibre/__init__.py
@@ -30,7 +30,12 @@
try:
locale.setlocale(locale.LC_ALL, '')
except:
- pass
+ dl = locale.getdefaultlocale()
+ try:
+ if dl:
+ locale.setlocale(dl[0])
+ except:
+ pass
try:
preferred_encoding = locale.getpreferredencoding()
diff --git a/src/calibre/ebooks/lrf/fb2/convert_from.py b/src/calibre/ebooks/lrf/fb2/convert_from.py
index 29ceaa11cf..27c55757be 100644
--- a/src/calibre/ebooks/lrf/fb2/convert_from.py
+++ b/src/calibre/ebooks/lrf/fb2/convert_from.py
@@ -3,15 +3,13 @@
"""
Convert .fb2 files to .lrf
"""
-import os, sys, tempfile, subprocess, shutil, logging, glob
+import os, sys, tempfile, shutil, logging
+from base64 import b64decode
-from calibre.ptempfile import PersistentTemporaryFile
from calibre.ebooks.lrf import option_parser as lrf_option_parser
from calibre.ebooks.metadata.meta import get_metadata
-from calibre.ebooks import ConversionError
from calibre.ebooks.lrf.html.convert_from import process_file as html_process_file
from calibre import setup_cli_handlers, __appname__
-from calibre.ebooks.BeautifulSoup import BeautifulStoneSoup
from calibre.resources import fb2_xsl
def option_parser():
@@ -22,25 +20,27 @@ def option_parser():
%prog converts mybook.fb2 to mybook.lrf'''))
parser.add_option('--debug-html-generation', action='store_true', default=False,
dest='debug_html_generation', help=_('Print generated HTML to stdout and quit.'))
+ parser.add_option('--keep-intermediate-files', action='store_true', default=False,
+ help=_('Keep generated HTML files after completing conversion to LRF.'))
return parser
+def extract_embedded_content(doc):
+ for elem in doc.xpath('./*'):
+ if 'binary' in elem.tag and elem.attrib.has_key('id'):
+ fname = elem.attrib['id']
+ data = b64decode(elem.text.strip())
+ open(fname, 'wb').write(data)
def generate_html(fb2file, encoding, logger):
from lxml import etree
- tdir = tempfile.mkdtemp(prefix=__appname__+'_')
- ofile = os.path.join(tdir, 'index.xml')
+ tdir = tempfile.mkdtemp(prefix=__appname__+'_fb2_')
cwd = os.getcwdu()
os.chdir(tdir)
try:
logger.info('Parsing XML...')
parser = etree.XMLParser(recover=True, no_network=True)
- try:
- doc = etree.parse(fb2file, parser)
- except:
- raise
- logger.info('Parsing failed. Trying to clean up XML...')
- soup = BeautifulStoneSoup(open(fb2file, 'rb').read())
- doc = etree.fromstring(str(soup))
+ doc = etree.parse(fb2file, parser)
+ extract_embedded_content(doc)
logger.info('Converting XML to HTML...')
styledoc = etree.fromstring(fb2_xsl)
@@ -72,7 +72,7 @@ def process_file(path, options, logger=None):
options.output = os.path.abspath(os.path.basename(os.path.splitext(path)[0]) + ext)
options.output = os.path.abspath(os.path.expanduser(options.output))
if not mi.title:
- mi.title = os.path.splitext(os.path.basename(rtf))[0]
+ mi.title = os.path.splitext(os.path.basename(fb2))[0]
if (not options.title or options.title == 'Unknown'):
options.title = mi.title
if (not options.author or options.author == 'Unknown') and mi.authors:
@@ -85,7 +85,7 @@ def process_file(path, options, logger=None):
html_process_file(htmlfile, options, logger)
finally:
os.chdir(cwd)
- if hasattr(options, 'keep_intermediate_files') and options.keep_intermediate_files:
+ if getattr(options, 'keep_intermediate_files', False):
logger.debug('Intermediate files in '+ tdir)
else:
shutil.rmtree(tdir)
diff --git a/src/calibre/ebooks/lrf/fb2/fb2.xsl b/src/calibre/ebooks/lrf/fb2/fb2.xsl
index 75f3c245ed..7a977aee76 100644
--- a/src/calibre/ebooks/lrf/fb2/fb2.xsl
+++ b/src/calibre/ebooks/lrf/fb2/fb2.xsl
@@ -128,21 +128,40 @@
-
-
-
-
-
-
-
+
+
+
+ None
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TOC_
+
+
@@ -166,7 +185,9 @@
-
+
+
+
diff --git a/src/calibre/ebooks/metadata/fb2.py b/src/calibre/ebooks/metadata/fb2.py
index 5bffb47409..672fc3e9ee 100644
--- a/src/calibre/ebooks/metadata/fb2.py
+++ b/src/calibre/ebooks/metadata/fb2.py
@@ -5,7 +5,8 @@
'''Read meta information from fb2 files'''
-import sys, os
+import sys, os, mimetypes
+from base64 import b64decode
from calibre.ebooks.BeautifulSoup import BeautifulStoneSoup
from calibre.ebooks.metadata import MetaInformation
@@ -18,15 +19,30 @@ def get_metadata(stream):
author= [firstname+" "+lastname]
title = soup.find("book-title").string
comments = soup.find("annotation")
+ cp = soup.find('coverpage')
+ cdata = None
+ if cp:
+ cimage = cp.find('image', attrs={'l:href':True})
+ if cimage:
+ id = cimage['l:href'].replace('#', '')
+ binary = soup.find('binary', id=id, attrs={'content-type':True})
+ if binary:
+ mt = binary['content-type']
+ exts = mimetypes.guess_all_extensions(mt)
+ if not exts:
+ exts = ['.jpg']
+ cdata = (exts[0][1:], b64decode(binary.string.strip()))
+
if comments and len(comments) > 1:
- comments = comments.p.contents[0]
+ comments = comments.p.contents[0]
series = soup.find("sequence")
- # series_index = series.index
mi = MetaInformation(title, author)
mi.comments = comments
+ mi.author_sort = lastname+'; '+firstname
if series:
mi.series = series.get('name', None)
- # mi.series_index = series_index
+ if cdata:
+ mi.cover_data = cdata
return mi
def main(args=sys.argv):
diff --git a/src/calibre/ebooks/metadata/toc.py b/src/calibre/ebooks/metadata/toc.py
index a966dd6fae..dc039a7f80 100644
--- a/src/calibre/ebooks/metadata/toc.py
+++ b/src/calibre/ebooks/metadata/toc.py
@@ -70,7 +70,7 @@ def read_from_opf(self, opfreader):
break
if toc is not None:
- if toc.lower() != 'ncx':
+ if toc.lower() not in ('ncx', 'ncxtoc'):
toc = urlparse(unquote(toc))[2]
toc = toc.replace('/', os.sep)
if not os.path.isabs(toc):
@@ -88,6 +88,10 @@ def read_from_opf(self, opfreader):
traceback.print_exc(file=sys.stdout)
print 'Continuing anyway'
else:
+ path = opfreader.manifest.item(toc.lower())
+ if path and os.access(path, os.R_OK):
+ self.read_ncx_toc(path)
+ return
cwd = os.path.abspath(self.base_path)
m = glob.glob(os.path.join(cwd, '*.ncx'))
if m:
diff --git a/src/calibre/gui2/library.py b/src/calibre/gui2/library.py
index 70f92e2805..76527c3034 100644
--- a/src/calibre/gui2/library.py
+++ b/src/calibre/gui2/library.py
@@ -574,7 +574,7 @@ def deletion_done(self, id, succeeded=True):
for row in rows:
if not succeeded:
indices = self.row_indices(self.index(row, 0))
- self.emit(SIGNAL('dataChanged(QModelIndex, QModelIndex)'), indices[0], indices[-1])
+ self.emit(SIGNAL('dataChanged(QModelIndex, QModelIndex)'), indices[0], indices[-1])
def paths_deleted(self, paths):
self.map = list(range(0, len(self.db)))
@@ -691,7 +691,7 @@ def current_changed(self, current, previous):
dt = item.datetime
dt = datetime(*dt[0:6])
dt = dt - timedelta(seconds=time.timezone) + timedelta(hours=time.daylight)
- data[_('Timestamp')] = dt.ctime()
+ data[_('Timestamp')] = dt.strftime('%a %b %d %H:%M:%S %Y')
data[_('Tags')] = ', '.join(item.tags)
self.emit(SIGNAL('new_bookdisplay_data(PyQt_PyObject)'), data)
diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py
index d09922848f..5dafe3c683 100644
--- a/src/calibre/gui2/main.py
+++ b/src/calibre/gui2/main.py
@@ -59,6 +59,9 @@ def set_default_thumbnail(self, height):
def __init__(self, single_instance, opts, parent=None):
MainWindow.__init__(self, opts, parent)
+ # Initialize fontconfig in a separate thread as this can be a lengthy
+ # process if run for the first time on this machine
+ self.fc = __import__('calibre.utils.fontconfig', fromlist=1)
self.single_instance = single_instance
if self.single_instance is not None:
self.connect(self.single_instance, SIGNAL('message_received(PyQt_PyObject)'),
diff --git a/src/calibre/library/cli.py b/src/calibre/library/cli.py
index 6e4ceb95b8..0e972cb20b 100644
--- a/src/calibre/library/cli.py
+++ b/src/calibre/library/cli.py
@@ -170,7 +170,8 @@ def do_add(db, paths, one_book_per_directory, recurse, add_duplicates):
for mi, formats in dir_dups:
db.import_book(mi, formats)
else:
- print >>sys.stderr, _('The following books were not added as they already exist in the database (see --duplicates option):')
+ if dir_dups or file_duplicates:
+ print >>sys.stderr, _('The following books were not added as they already exist in the database (see --duplicates option):')
for mi, formats in dir_dups:
title = mi.title
if isinstance(title, unicode):
diff --git a/src/calibre/linux_installer.py b/src/calibre/linux_installer.py
index db9c8dd1b1..145b255b05 100644
--- a/src/calibre/linux_installer.py
+++ b/src/calibre/linux_installer.py
@@ -240,13 +240,21 @@ def do_postinstall(destdir):
os.chdir(cwd)
def download_tarball():
- pb = ProgressBar(TerminalController(sys.stdout), 'Downloading calibre...')
+ try:
+ pb = ProgressBar(TerminalController(sys.stdout), 'Downloading calibre...')
+ except ValueError:
+ print 'Downloading calibre...'
+ pb = None
src = urllib2.urlopen(MOBILEREAD+'calibre-%version-i686.tar.bz2')
size = int(src.info()['content-length'])
f = tempfile.NamedTemporaryFile()
while f.tell() < size:
f.write(src.read(4*1024))
- pb.update(f.tell()/float(size))
+ percent = f.tell()/float(size)
+ if pb is not None:
+ pb.update(percent)
+ else:
+ print '%d%%, '%int(percent*100),
f.seek(0)
return f
@@ -269,4 +277,4 @@ def main(args=sys.argv):
return 0
if __name__ == '__main__':
- sys.exit(main())
\ No newline at end of file
+ sys.exit(main())
diff --git a/src/calibre/trac/plugins/Changelog.py b/src/calibre/trac/plugins/Changelog.py
index 35c54b1bda..ff15329859 100644
--- a/src/calibre/trac/plugins/Changelog.py
+++ b/src/calibre/trac/plugins/Changelog.py
@@ -69,4 +69,4 @@ def expand_macro(self, formatter, name, args):
if __name__ == '__main__':
print bzr_log_to_txt()
-
\ No newline at end of file
+
diff --git a/src/calibre/trac/plugins/templates/pyinstaller.html b/src/calibre/trac/plugins/templates/pyinstaller.html
index c04fd13da4..4061b0aadc 100644
--- a/src/calibre/trac/plugins/templates/pyinstaller.html
+++ b/src/calibre/trac/plugins/templates/pyinstaller.html
@@ -44,4 +44,4 @@