Sync to trunk.

This commit is contained in:
John Schember 2009-07-26 15:05:46 -04:00
commit bfbcd0fba5
17 changed files with 121 additions and 172 deletions

View file

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

View file

@ -8,7 +8,7 @@
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 @@ def upload_books(self, files, names, on_card=None, end_session=True,
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):

View file

@ -8,7 +8,7 @@
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):

View file

@ -15,7 +15,7 @@
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):
'''

View file

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

View file

@ -18,38 +18,38 @@
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 @@ def attrs_to_dict(cls, tag, exclude=('objid',)):
continue
result[str(key)] = val
return result
def text_tag_to_element(self, tag):
map = {
'span' : Span,
@ -77,7 +77,7 @@ def text_tag_to_element(self, tag):
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 @@ def process_text_element(self, tag, elem):
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 @@ def process_paragraph(self, tag):
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 @@ def process_text_block(self, tag):
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 @@ def fourth_pass(self):
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 @@ def third_pass(self):
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 @@ def third_pass(self):
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 @@ def second_pass(self):
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 @@ def tag_to_string(cls, tag):
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 @@ def me(base, tagname):
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 @@ def me(base, tagname):
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())
sys.exit(main())

View file

@ -21,7 +21,8 @@
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 @@ def extract_content(self, output_dir, parse_cache):
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'):

View file

@ -65,9 +65,9 @@ def insert_metadata(self, mi):
if not comments.strip():
comments = ''
comments = comments.replace('\r\n', '\n').replace('\n\n', '<br/><br/>')
series = '<b>Series: </b>' + mi.series if mi.series else ''
series = '<b>Series: </b>' + 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 @@ def insert_metadata(self, mi):
except:
tags = []
if tags:
tags = '<b>Tags: </b>' + self.opts.dest.tags_to_string(tags)
tags = '<b>Tags: </b>' + escape(self.opts.dest.tags_to_string(tags))
else:
tags = ''
try:
@ -84,8 +84,8 @@ def insert_metadata(self, mi):
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)

View file

@ -57,6 +57,7 @@
import re
from calibre.ebooks.unidecode.unicodepoints import CODEPOINTS
from calibre.constants import preferred_encoding
class Unidecoder(object):
@ -70,7 +71,10 @@ def decode(self, text):
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 @@ def replace_point(self, codepoint):
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(

View file

@ -342,6 +342,8 @@ def __init__(self, title='Choose Files',
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

View file

@ -21,7 +21,7 @@
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 @@ def send_by_mail(self, to, fmts, delete_from_library, send_ids=None,
'\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 @@ def sync_news(self, send_ids=None, do_auto_convert=True):
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 @@ def sync_to_device(self, on_card, delete_from_library,
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)

View file

@ -526,3 +526,11 @@ def accept(self):
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)

View file

@ -14,8 +14,9 @@
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 @@ def _add_books(self, paths, to_device, on_card=None):
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 @@ def delete_books(self, checked):
'removed from your computer. Are you sure?')
+'</p>', 'library_delete_books', self):
return
ci = view.currentIndex()
row = None
if ci.isValid():
row = ci.row()
view.model().delete_books(rows)
if row is not None:
ci = view.model().index(row, 0)
if ci.isValid():
view.setCurrentIndex(ci)
sm = view.selectionModel()
sm.select(ci, sm.Select)
else:
if self.stack.currentIndex() == 1:
view = self.memory_view

View file

@ -34,7 +34,7 @@
from calibre.ptempfile import PersistentTemporaryFile
from calibre.customize.ui import run_plugins_on_import
from calibre import sanitize_file_name
from calibre.utils.filenames import ascii_filename
from calibre.ebooks import BOOK_EXTENSIONS
if iswindows:
@ -652,8 +652,8 @@ def construct_path_name(self, id):
authors = self.authors(id, index_is_id=True)
if not authors:
authors = _('Unknown')
author = sanitize_file_name(authors.split(',')[0][:self.PATH_LIMIT]).decode(filesystem_encoding, 'ignore')
title = sanitize_file_name(self.title(id, index_is_id=True)[:self.PATH_LIMIT]).decode(filesystem_encoding, 'ignore')
author = ascii_filename(authors.split(',')[0][:self.PATH_LIMIT]).decode(filesystem_encoding, 'ignore')
title = ascii_filename(self.title(id, index_is_id=True)[:self.PATH_LIMIT]).decode(filesystem_encoding, 'ignore')
path = author + '/' + title + ' (%d)'%id
return path
@ -664,8 +664,8 @@ def construct_file_name(self, id):
authors = self.authors(id, index_is_id=True)
if not authors:
authors = _('Unknown')
author = sanitize_file_name(authors.split(',')[0][:self.PATH_LIMIT]).decode(filesystem_encoding, 'replace')
title = sanitize_file_name(self.title(id, index_is_id=True)[:self.PATH_LIMIT]).decode(filesystem_encoding, 'replace')
author = ascii_filename(authors.split(',')[0][:self.PATH_LIMIT]).decode(filesystem_encoding, 'replace')
title = ascii_filename(self.title(id, index_is_id=True)[:self.PATH_LIMIT]).decode(filesystem_encoding, 'replace')
name = title + ' - ' + author
while name.endswith('.'):
name = name[:-1]
@ -1520,12 +1520,12 @@ def get_data_as_dict(self, prefix=None, authors_as_string=False):
x['cover'] = os.path.join(path, 'cover.jpg')
if not self.has_cover(x['id'], index_is_id=True):
x['cover'] = None
path += os.sep + self.construct_file_name(record[FIELD_MAP['id']]) + '.%s'
formats = self.formats(record[FIELD_MAP['id']], index_is_id=True)
if formats:
for fmt in formats.split(','):
x['formats'].append(path%fmt.lower())
x['fmt_'+fmt.lower()] = path%fmt.lower()
path = self.format_abspath(x['id'], fmt, index_is_id=True)
x['formats'].append(path)
x['fmt_'+fmt.lower()] = path
x['available_formats'] = [i.upper() for i in formats.split(',')]
return data
@ -1602,12 +1602,12 @@ def export_to_dir(self, dir, indices, byauthor=False, single_dir=False,
by_author[au] = []
by_author[au].append(index)
for au in by_author.keys():
apath = os.path.join(dir, sanitize_file_name(au))
apath = os.path.join(dir, ascii_filename(au))
if not single_dir and not os.path.exists(apath):
os.mkdir(apath)
for idx in by_author[au]:
title = re.sub(r'\s', ' ', self.title(idx, index_is_id=index_is_id))
tpath = os.path.join(apath, sanitize_file_name(title))
tpath = os.path.join(apath, ascii_filename(title))
id = idx if index_is_id else self.id(idx)
id = str(id)
if not single_dir and not os.path.exists(tpath):
@ -1621,10 +1621,10 @@ def export_to_dir(self, dir, indices, byauthor=False, single_dir=False,
mi.authors = [_('Unknown')]
cdata = self.cover(int(id), index_is_id=True)
if cdata is not None:
cname = sanitize_file_name(name)+'.jpg'
cname = ascii_filename(name)+'.jpg'
open(os.path.join(base, cname), 'wb').write(cdata)
mi.cover = cname
with open(os.path.join(base, sanitize_file_name(name)+'.opf'),
with open(os.path.join(base, ascii_filename(name)+'.opf'),
'wb') as f:
f.write(metadata_to_opf(mi))
@ -1636,7 +1636,7 @@ def export_to_dir(self, dir, indices, byauthor=False, single_dir=False,
if not data:
continue
fname = name +'.'+fmt.lower()
fname = sanitize_file_name(fname)
fname = ascii_filename(fname)
f = open(os.path.join(base, fname), 'w+b')
f.write(data)
f.flush()
@ -1671,7 +1671,7 @@ def export_single_format_to_dir(self, dir, indices, format,
if not au:
au = _('Unknown')
fname = '%s - %s.%s'%(title, au, format.lower())
fname = sanitize_file_name(fname)
fname = ascii_filename(fname)
if not os.path.exists(dir):
os.makedirs(dir)
f = open(os.path.join(dir, fname), 'w+b')

View file

@ -82,10 +82,6 @@ sudo python -c "import urllib2; exec urllib2.urlopen('http://calibre.kovidgoyal.
</pre>
<h4>Note</h4>
<ul>
<li>On some linux distributions, you have to install the
libphonon (may be called libphonon4) package for calibre
to work.
</li>
<li>
When running the command line utilities,
they will segfault after completion. This can

View file

@ -1,97 +1,23 @@
# -*- coding: utf-8 -*-
'''
Make strings safe for use as ASCII filenames, while trying to preserve as much
Make strings safe for use as ASCII filenames, while trying to preserve as much
meaning as possible.
'''
import re, string
from calibre.ebooks.unidecode.unidecoder import Unidecoder
from calibre import sanitize_file_name
from calibre.constants import preferred_encoding
udc = Unidecoder()
MAP = {
u"" : "'",
u"" : "'",
u"«" : '"',
u"»" : '"',
u"" : "...",
u"" : "#",
u"Щ" : "Shh",
u"Ё" : "Jo",
u"Ж" : "Zh",
u"Ц" : "C",
u"Ч" : "Ch",
u"Ш" : "Sh",
u"Ы" : "Y",
u"Ю" : "Ju",
u"Я" : "Ja",
u"Б" : "B",
u"Г" : "G",
u"Д" : "D",
u"И" : "I",
u"Й" : "J",
u"К" : "K",
u"Л" : "L",
u"П" : "P",
u"Ф" : "F",
u"Э" : "E",
u"Ъ" : "`",
u"Ь" : "'",
u"щ" : "shh",
u"ё" : "jo",
u"ж" : "zh",
u"ц" : "c",
u"ч" : "ch",
u"ш" : "sh",
u"ы" : "y",
u"ю" : "ju",
u"я" : "ja",
u"б" : "b",
u"в" : "v",
u"г" : "g",
u"д" : "d",
u"з" : "z",
u"и" : "i",
u"й" : "j",
u"к" : "k",
u"л" : "l",
u"м" : "m",
u"н" : "n",
u"о" : "o",
u"п" : "p",
u"т" : "t",
u"ф" : "f",
u"э" : "e",
u"ъ" : "`",
u"ь" : "'",
u"А" : "A",
u"В" : "V",
u"Е" : "Je",
u"З" : "Z",
u"М" : "M",
u"Н" : "N",
u"О" : "O",
u"Р" : "R",
u"С" : "S",
u"Т" : "T",
u"У" : "U",
u"Х" : "Kh",
u"Є" : "Je",
u"Ї" : "Ji",
u"а" : "a",
u"е" : "je",
u"р" : "r",
u"с" : "s",
u"у" : "u",
u"х" : "kh",
u"є" : "je",
} #: Translation table
def ascii_text(orig):
try:
ascii = udc.decode(orig)
except:
if isinstance(orig, unicode):
ascii = orig.encode('ascii', 'replace')
ascii = orig.decode(preferred_encoding,
'replace').encode('ascii', 'replace')
return ascii
for c in string.whitespace:
MAP[c] = ' '
PAT = re.compile('['+u''.join(MAP.keys())+']')
def ascii_filename(orig):
orig = PAT.sub(lambda m:MAP[m.group()], orig)
buf = []
for i in range(len(orig)):
val = ord(orig[i])
buf.append('_' if val < 33 or val > 126 else orig[i])
return (''.join(buf)).encode('ascii')
return sanitize_file_name(ascii_text(orig).replace('?', '_'))

View file

@ -14,8 +14,8 @@
from PIL import Image
from cStringIO import StringIO
from calibre import browser, sanitize_file_name, \
relpath, unicode_path
from calibre import browser, relpath, unicode_path
from calibre.utils.filenames import ascii_filename
from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag
from calibre.ebooks.chardet import xml_to_unicode
from calibre.utils.config import OptionParser
@ -313,7 +313,7 @@ def process_images(self, soup, baseurl):
self.log.exception('Could not fetch image %s'% iurl)
continue
c += 1
fname = sanitize_file_name('img'+str(c)+ext)
fname = ascii_filename('img'+str(c)+ext)
if isinstance(fname, unicode):
fname = fname.encode('ascii', 'replace')
imgpath = os.path.join(diskpath, fname+'.jpg')
@ -416,7 +416,7 @@ def process_links(self, soup, baseurl, recursion_level, into_dir='links'):
if not isinstance(_fname, unicode):
_fname.decode('latin1', 'replace')
_fname = _fname.encode('ascii', 'replace').replace('%', '').replace(os.sep, '')
_fname = sanitize_file_name(_fname)
_fname = ascii_filename(_fname)
_fname = os.path.splitext(_fname)[0]+'.xhtml'
res = os.path.join(linkdiskpath, _fname)
self.downloaded_paths.append(res)