diff --git a/installer/linux/freeze.py b/installer/linux/freeze.py
index 23c4ea7d73..352211379b 100644
--- a/installer/linux/freeze.py
+++ b/installer/linux/freeze.py
@@ -49,6 +49,7 @@ def freeze():
'/usr/lib/libMagickCore.so',
'/usr/lib/libgcrypt.so.11',
'/usr/lib/libgpg-error.so.0',
+ '/usr/lib/libphonon.so.4',
]
binary_includes += [os.path.join(QTDIR, 'lib%s.so.4'%x) for x in QTDLLS]
diff --git a/src/calibre/devices/cybookg3/driver.py b/src/calibre/devices/cybookg3/driver.py
index 9976a0f02e..a8ce905b00 100644
--- a/src/calibre/devices/cybookg3/driver.py
+++ b/src/calibre/devices/cybookg3/driver.py
@@ -8,7 +8,7 @@ import os
import shutil
from itertools import cycle
-from calibre import sanitize_file_name as sanitize
+from calibre.utils.filenames import ascii_filename as sanitize
from calibre.devices.usbms.driver import USBMS
import calibre.devices.cybookg3.t2b as t2b
@@ -98,7 +98,7 @@ class CYBOOKG3(USBMS):
self.report_progress(i / float(len(files)), _('Transferring books to device...'))
self.report_progress(1.0, _('Transferring books to device...'))
-
+
return zip(paths, cycle([on_card]))
def delete_books(self, paths, end_session=True):
diff --git a/src/calibre/devices/jetbook/driver.py b/src/calibre/devices/jetbook/driver.py
index 9e91f4cfa9..c6668364a7 100644
--- a/src/calibre/devices/jetbook/driver.py
+++ b/src/calibre/devices/jetbook/driver.py
@@ -8,7 +8,7 @@ import os, re, sys, shutil
from itertools import cycle
from calibre.devices.usbms.driver import USBMS
-from calibre import sanitize_file_name as sanitize
+from calibre.utils.filenames import ascii_filename as sanitize
from calibre.ebooks.metadata import string_to_authors
class JETBOOK(USBMS):
diff --git a/src/calibre/devices/usbms/device.py b/src/calibre/devices/usbms/device.py
index 8bbfd58043..007f132b24 100644
--- a/src/calibre/devices/usbms/device.py
+++ b/src/calibre/devices/usbms/device.py
@@ -15,7 +15,7 @@ from calibre.devices.interface import DevicePlugin
from calibre.devices.errors import DeviceError
from calibre.devices.usbms.deviceconfig import DeviceConfig
from calibre import iswindows, islinux, isosx, __appname__
-from calibre import sanitize_file_name as sanitize
+from calibre.utils.filenames import ascii_filename as sanitize
class Device(DeviceConfig, DevicePlugin):
'''
diff --git a/src/calibre/ebooks/comic/input.py b/src/calibre/ebooks/comic/input.py
index 2eed12de0c..c039b06676 100755
--- a/src/calibre/ebooks/comic/input.py
+++ b/src/calibre/ebooks/comic/input.py
@@ -253,7 +253,6 @@ def process_pages(pages, opts, update, tdir):
for job in jobs:
if job.failed:
- raw_input()
raise Exception(_('Failed to process comic: \n\n%s')%
job.log_file.read())
pages, failures_ = job.result
diff --git a/src/calibre/ebooks/lrf/lrs/convert_from.py b/src/calibre/ebooks/lrf/lrs/convert_from.py
index 86a97aa70b..e0ce88c2b9 100644
--- a/src/calibre/ebooks/lrf/lrs/convert_from.py
+++ b/src/calibre/ebooks/lrf/lrs/convert_from.py
@@ -18,38 +18,38 @@ from calibre.ebooks.lrf.pylrs.pylrs import Book, PageStyle, TextStyle, \
from calibre.ebooks.chardet import xml_to_unicode
class LrsParser(object):
-
- SELF_CLOSING_TAGS = [i.lower() for i in ['CR', 'Plot', 'NoBR', 'Space',
- 'PutObj', 'RuledLine',
+
+ SELF_CLOSING_TAGS = [i.lower() for i in ['CR', 'Plot', 'NoBR', 'Space',
+ 'PutObj', 'RuledLine',
'Plot', 'SetDefault', 'BookSetting', 'RegistFont',
'PageStyle', 'TextStyle', 'BlockStyle', 'JumpTo',
'ImageStream', 'Image']]
-
+
def __init__(self, stream, logger):
self.logger = logger
src = stream.read()
self.soup = BeautifulStoneSoup(xml_to_unicode(src)[0],
- convertEntities=BeautifulStoneSoup.XML_ENTITIES,
+ convertEntities=BeautifulStoneSoup.XML_ENTITIES,
selfClosingTags=self.SELF_CLOSING_TAGS)
self.objects = {}
for obj in self.soup.findAll(objid=True):
self.objects[obj['objid']] = obj
-
+
self.parsed_objects = {}
self.first_pass()
self.second_pass()
self.third_pass()
self.fourth_pass()
self.fifth_pass()
-
+
def fifth_pass(self):
for tag in self.soup.findAll(['canvas', 'header', 'footer']):
canvas = self.parsed_objects[tag.get('objid')]
for po in tag.findAll('putobj'):
canvas.put_object(self.parsed_objects[po.get('refobj')],
po.get('x1'), po.get('y1'))
-
-
+
+
@classmethod
def attrs_to_dict(cls, tag, exclude=('objid',)):
result = {}
@@ -58,7 +58,7 @@ class LrsParser(object):
continue
result[str(key)] = val
return result
-
+
def text_tag_to_element(self, tag):
map = {
'span' : Span,
@@ -77,7 +77,7 @@ class LrsParser(object):
settings = self.attrs_to_dict(tag)
settings.pop('spanstyle', '')
return map[tag.name](**settings)
-
+
def process_text_element(self, tag, elem):
for item in tag.contents:
if isinstance(item, NavigableString):
@@ -86,8 +86,8 @@ class LrsParser(object):
subelem = self.text_tag_to_element(item)
elem.append(subelem)
self.process_text_element(item, subelem)
-
-
+
+
def process_paragraph(self, tag):
p = Paragraph()
contents = [i for i in tag.contents]
@@ -104,7 +104,7 @@ class LrsParser(object):
p.append(elem)
self.process_text_element(item, elem)
return p
-
+
def process_text_block(self, tag):
tb = self.parsed_objects[tag.get('objid')]
for item in tag.contents:
@@ -119,25 +119,25 @@ class LrsParser(object):
elem = self.text_tag_to_element(item)
self.process_text_element(item, elem)
p.append(elem)
-
+
def fourth_pass(self):
for tag in self.soup.findAll('page'):
page = self.parsed_objects[tag.get('objid')]
self.book.append(page)
- for block_tag in tag.findAll(['canvas', 'imageblock', 'textblock',
+ for block_tag in tag.findAll(['canvas', 'imageblock', 'textblock',
'ruledline', 'simpletextblock']):
if block_tag.name == 'ruledline':
page.append(RuledLine(**self.attrs_to_dict(block_tag)))
else:
page.append(self.parsed_objects[block_tag.get('objid')])
-
+
for tag in self.soup.find('objects').findAll('button'):
jt = tag.find('jumpto')
tb = self.parsed_objects[jt.get('refobj')]
jb = JumpButton(tb)
self.book.append(jb)
self.parsed_objects[tag.get('objid')] = jb
-
+
for tag in self.soup.findAll(['textblock', 'simpletextblock']):
self.process_text_block(tag)
toc = self.soup.find('toc')
@@ -145,11 +145,11 @@ class LrsParser(object):
for tag in toc.findAll('toclabel'):
label = self.tag_to_string(tag)
self.book.addTocEntry(label, self.parsed_objects[tag.get('refobj')])
-
-
+
+
def third_pass(self):
map = {
- 'page' : (Page, ['pagestyle', 'evenfooterid',
+ 'page' : (Page, ['pagestyle', 'evenfooterid',
'oddfooterid', 'evenheaderid', 'oddheaderid']),
'textblock' : (TextBlock, ['textstyle', 'blockstyle']),
'simpletextblock' : (TextBlock, ['textstyle', 'blockstyle']),
@@ -167,7 +167,8 @@ class LrsParser(object):
settings = self.attrs_to_dict(tag, map[tag.name][1]+['objid', 'objlabel'])
for a in ('pagestyle', 'blockstyle', 'textstyle'):
label = tag.get(a, False)
- if label:
+ if label and \
+ (label in self._style_labels or label in self.parsed_objects):
_obj = self.parsed_objects[label] if \
self.parsed_objects.has_key(label) else \
self._style_labels[label]
@@ -181,9 +182,9 @@ class LrsParser(object):
if tag.has_key('canvaswidth'):
args += [tag.get('canvaswidth'), tag.get('canvasheight')]
self.parsed_objects[id] = map[tag.name][0](*args, **settings)
-
-
-
+
+
+
def second_pass(self):
map = {
'pagestyle' : (PageStyle, ['stylelabel', 'evenheaderid', 'oddheaderid', 'evenfooterid', 'oddfooterid']),
@@ -207,8 +208,8 @@ class LrsParser(object):
self._style_labels[x] = self.parsed_objects[id]
if tag.name == 'registfont':
self.book.append(self.parsed_objects[id])
-
-
+
+
@classmethod
def tag_to_string(cls, tag):
'''
@@ -226,20 +227,20 @@ class LrsParser(object):
res = cls.tag_to_string(item)
if res:
strings.append(res)
- return u''.join(strings)
-
+ return u''.join(strings)
+
def first_pass(self):
info = self.soup.find('bbebxylog').find('bookinformation').find('info')
bookinfo = info.find('bookinfo')
docinfo = info.find('docinfo')
-
+
def me(base, tagname):
tag = base.find(tagname.lower())
if tag is None:
return ('', '', '')
tag = (self.tag_to_string(tag), tag.get('reading') if tag.has_key('reading') else '')
return tag
-
+
title = me(bookinfo, 'Title')
author = me(bookinfo, 'Author')
publisher = me(bookinfo, 'Publisher')
@@ -250,12 +251,12 @@ class LrsParser(object):
creator = me(docinfo, 'Creator')[0]
producer = me(docinfo, 'Producer')[0]
bookid = me(bookinfo, 'BookID')[0]
-
+
sd = self.soup.find('setdefault')
sd = StyleDefault(**self.attrs_to_dict(sd, ['page_tree_id', 'rubyalignandadjust']))
bs = self.soup.find('booksetting')
bs = BookSetting(**self.attrs_to_dict(bs, []))
-
+
settings = {}
thumbnail = self.soup.find('cthumbnail')
if thumbnail is not None:
@@ -264,23 +265,23 @@ class LrsParser(object):
settings['thumbnail'] = f
else:
print _('Could not read from thumbnail file:'), f
-
+
self.book = Book(title=title, author=author, publisher=publisher,
category=category, classification=classification,
freetext=freetext, language=language, creator=creator,
producer=producer, bookid=bookid, setdefault=sd,
booksetting=bs, **settings)
-
+
for hdr in self.soup.findAll(['header', 'footer']):
elem = Header if hdr.name == 'header' else Footer
- self.parsed_objects[hdr.get('objid')] = elem(**self.attrs_to_dict(hdr))
-
+ self.parsed_objects[hdr.get('objid')] = elem(**self.attrs_to_dict(hdr))
+
def render(self, file, to_lrs=False):
if to_lrs:
self.book.renderLrs(file, 'utf-8')
else:
self.book.renderLrf(file)
-
+
def option_parser():
parser = OptionParser(usage=_('%prog [options] file.lrs\nCompile an LRS file into an LRF file.'))
@@ -299,7 +300,7 @@ def main(args=sys.argv, logger=None):
level = logging.DEBUG if opts.verbose else logging.INFO
logger = logging.getLogger('lrs2lrf')
setup_cli_handlers(logger, level)
-
+
if len(args) != 2:
parser.print_help()
return 1
@@ -310,7 +311,7 @@ def main(args=sys.argv, logger=None):
if opts.verbose:
import warnings
warnings.defaultaction = 'error'
-
+
logger.info('Parsing LRS file...')
converter = LrsParser(open(args[1], 'rb'), logger)
logger.info('Writing to output file...')
@@ -320,4 +321,4 @@ def main(args=sys.argv, logger=None):
if __name__ == '__main__':
- sys.exit(main())
\ No newline at end of file
+ sys.exit(main())
diff --git a/src/calibre/ebooks/mobi/reader.py b/src/calibre/ebooks/mobi/reader.py
index 3d46668ee9..eed42bce46 100644
--- a/src/calibre/ebooks/mobi/reader.py
+++ b/src/calibre/ebooks/mobi/reader.py
@@ -21,7 +21,8 @@ except ImportError:
from lxml import html, etree
-from calibre import entity_to_unicode, sanitize_file_name
+from calibre import entity_to_unicode
+from calibre.utils.filenames import ascii_filename
from calibre.ptempfile import TemporaryDirectory
from calibre.ebooks import DRMError
from calibre.ebooks.chardet import ENCODING_PATS
@@ -374,7 +375,7 @@ class MobiReader(object):
fname = self.name.encode('ascii', 'replace')
fname = re.sub(r'[\x08\x15\0]+', '', fname)
htmlfile = os.path.join(output_dir,
- sanitize_file_name(fname) + '.html')
+ ascii_filename(fname) + '.html')
try:
for ref in guide.xpath('descendant::reference'):
if ref.attrib.has_key('href'):
diff --git a/src/calibre/ebooks/oeb/transforms/jacket.py b/src/calibre/ebooks/oeb/transforms/jacket.py
index add9f85e08..6d36ef44fa 100644
--- a/src/calibre/ebooks/oeb/transforms/jacket.py
+++ b/src/calibre/ebooks/oeb/transforms/jacket.py
@@ -65,9 +65,9 @@ class Jacket(object):
if not comments.strip():
comments = ''
comments = comments.replace('\r\n', '\n').replace('\n\n', '
')
- series = 'Series: ' + mi.series if mi.series else ''
+ series = 'Series: ' + escape(mi.series if mi.series else '')
if series and mi.series_index is not None:
- series += ' [%s]'%mi.format_series_index()
+ series += escape(' [%s]'%mi.format_series_index())
tags = mi.tags
if not tags:
try:
@@ -75,7 +75,7 @@ class Jacket(object):
except:
tags = []
if tags:
- tags = 'Tags: ' + self.opts.dest.tags_to_string(tags)
+ tags = 'Tags: ' + escape(self.opts.dest.tags_to_string(tags))
else:
tags = ''
try:
@@ -84,8 +84,8 @@ class Jacket(object):
title = _('Unknown')
html = self.JACKET_TEMPLATE%dict(xmlns=XPNSMAP['h'],
title=escape(title), comments=escape(comments),
- jacket=escape(_('Book Jacket')), series=escape(series),
- tags=escape(tags))
+ jacket=escape(_('Book Jacket')), series=series,
+ tags=tags)
id, href = self.oeb.manifest.generate('jacket', 'jacket.xhtml')
root = etree.fromstring(html)
item = self.oeb.manifest.add(id, href, guess_type(href)[0], data=root)
diff --git a/src/calibre/ebooks/unidecode/unidecoder.py b/src/calibre/ebooks/unidecode/unidecoder.py
index 8da60d29e9..d31239a1dc 100644
--- a/src/calibre/ebooks/unidecode/unidecoder.py
+++ b/src/calibre/ebooks/unidecode/unidecoder.py
@@ -57,6 +57,7 @@ it under the same terms as Perl itself.
import re
from calibre.ebooks.unidecode.unicodepoints import CODEPOINTS
+from calibre.constants import preferred_encoding
class Unidecoder(object):
@@ -70,7 +71,10 @@ class Unidecoder(object):
try:
text = unicode(text)
except:
- text = text.decode('utf-8', 'ignore')
+ try:
+ text = text.decode(preferred_encoding)
+ except:
+ text = text.decode('utf-8', 'replace')
# Replace characters larger than 127 with their ASCII equivelent.
return re.sub('[^\x00-\x7f]', lambda x: self.replace_point(x.group()),
text)
@@ -80,7 +84,7 @@ class Unidecoder(object):
Returns the replacement character or ? if none can be found.
'''
try:
- # Splite the unicode character xABCD into parts 0xAB and 0xCD.
+ # Split the unicode character xABCD into parts 0xAB and 0xCD.
# 0xAB represents the group within CODEPOINTS to query and 0xCD
# represents the position in the list of characters for the group.
return CODEPOINTS[self.code_group(codepoint)][self.grouped_point(
diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py
index f5dcdcfebe..12f6fb2025 100644
--- a/src/calibre/gui2/__init__.py
+++ b/src/calibre/gui2/__init__.py
@@ -342,6 +342,8 @@ class FileDialog(QObject):
ftext += '%s (%s);;'%(text, ' '.join(extensions))
if add_all_files_filter or not ftext:
ftext += 'All files (*)'
+ if ftext.endswith(';;'):
+ ftext = ftext[:-2]
self.dialog_name = name if name else 'dialog_' + title
self.selected_files = None
diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py
index 19228afa92..ffbcb2e9e2 100644
--- a/src/calibre/gui2/device.py
+++ b/src/calibre/gui2/device.py
@@ -21,7 +21,7 @@ from calibre.gui2 import config, error_dialog, Dispatcher, dynamic, \
pixmap_to_data, warning_dialog, \
question_dialog
from calibre.ebooks.metadata import authors_to_string
-from calibre import sanitize_file_name, preferred_encoding
+from calibre import preferred_encoding
from calibre.utils.filenames import ascii_filename
from calibre.devices.errors import FreeSpaceError
from calibre.utils.smtp import compose_mail, sendmail, extract_email_address, \
@@ -542,7 +542,7 @@ class DeviceGUI(object):
'\n\n' + t + '\n\t' + _('by') + ' ' + a + '\n\n' + \
_('in the %s format.') %
os.path.splitext(f)[1][1:].upper())
- prefix = sanitize_file_name(t+' - '+a)
+ prefix = ascii_filename(t+' - '+a)
if not isinstance(prefix, unicode):
prefix = prefix.decode(preferred_encoding, 'replace')
attachment_names.append(prefix + os.path.splitext(f)[1])
@@ -693,7 +693,7 @@ class DeviceGUI(object):
rows_are_ids=True)
names = []
for mi in metadata:
- prefix = sanitize_file_name(mi['title'])
+ prefix = ascii_filename(mi['title'])
if not isinstance(prefix, unicode):
prefix = prefix.decode(preferred_encoding, 'replace')
prefix = ascii_filename(prefix)
@@ -758,7 +758,7 @@ class DeviceGUI(object):
a = mi['authors']
if not a:
a = _('Unknown')
- prefix = sanitize_file_name(t+' - '+a)
+ prefix = ascii_filename(t+' - '+a)
if not isinstance(prefix, unicode):
prefix = prefix.decode(preferred_encoding, 'replace')
prefix = ascii_filename(prefix)
diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py
index 10a81be9f5..d349298609 100644
--- a/src/calibre/gui2/dialogs/metadata_single.py
+++ b/src/calibre/gui2/dialogs/metadata_single.py
@@ -526,3 +526,11 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
QDialog.accept(self)
if callable(self.accepted_callback):
self.accepted_callback(self.id)
+
+ def reject(self, *args):
+ cf = getattr(self, 'cover_fetcher', None)
+ if cf is not None and hasattr(cf, 'terminate'):
+ cf.terminate()
+ cf.wait()
+
+ QDialog.reject(self, *args)
diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py
index b4b8494c64..3da3a33c69 100644
--- a/src/calibre/gui2/main.py
+++ b/src/calibre/gui2/main.py
@@ -14,8 +14,9 @@ from PyQt4.Qt import Qt, SIGNAL, QObject, QCoreApplication, QUrl, QTimer, \
QMessageBox, QStackedLayout
from PyQt4.QtSvg import QSvgRenderer
-from calibre import __version__, __appname__, sanitize_file_name, \
+from calibre import __version__, __appname__, \
iswindows, isosx, prints, patheq
+from calibre.utils.filenames import ascii_filename
from calibre.ptempfile import PersistentTemporaryFile
from calibre.utils.config import prefs, dynamic
from calibre.utils.ipc.server import Server
@@ -852,7 +853,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
def _files_added(self, paths=[], names=[], infos=[], on_card=None):
if paths:
self.upload_books(paths,
- list(map(sanitize_file_name, names)),
+ list(map(ascii_filename, names)),
infos, on_card=on_card)
self.status_bar.showMessage(
_('Uploading books to device.'), 2000)
@@ -888,7 +889,17 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
'removed from your computer. Are you sure?')
+'