From 1c3a8708146ef0c83d14a60e66490c351ef2ed57 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 12 Aug 2008 12:14:51 -0700 Subject: [PATCH] Transliterate filenames before saving to device --- src/calibre/gui2/main.py | 10 ++-- src/calibre/gui2/main_window.py | 8 ++- src/calibre/utils/filenames.py | 88 +++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 src/calibre/utils/filenames.py diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py index f0d168de0b..576b4f9a98 100644 --- a/src/calibre/gui2/main.py +++ b/src/calibre/gui2/main.py @@ -10,7 +10,7 @@ from PyQt4.QtGui import QPixmap, QColor, QPainter, QMenu, QIcon, QMessageBox, \ from PyQt4.QtSvg import QSvgRenderer from calibre import __version__, __appname__, islinux, sanitize_file_name, \ - Settings, iswindows, isosx + Settings, iswindows, isosx, preferred_encoding from calibre.ptempfile import PersistentTemporaryFile from calibre.ebooks.metadata.meta import get_metadata, get_filename_pat, set_filename_pat from calibre.devices.errors import FreeSpaceError @@ -45,6 +45,7 @@ from calibre.ebooks.metadata import MetaInformation from calibre.ebooks import BOOK_EXTENSIONS from calibre.ebooks.lrf import preferred_source_formats as LRF_PREFERRED_SOURCE_FORMATS from calibre.parallel import JobKilled +from calibre.utils.filenames import ascii_filename class Main(MainWindow, Ui_MainWindow): @@ -661,10 +662,9 @@ class Main(MainWindow, Ui_MainWindow): if not a: a = 'Unknown' prefix = sanitize_file_name(t+' - '+a) - if isinstance(prefix, unicode): - prefix = prefix.encode('ascii', 'ignore') - else: - prefix = prefix.decode('ascii', 'ignore').encode('ascii', 'ignore') + if not isinstance(prefix, unicode): + prefix = prefix.decode(preferred_encoding, 'replace') + prefix = ascii_filename(prefix) names.append('%s_%d%s'%(prefix, id, os.path.splitext(f)[1])) remove = [self.library_view.model().id(r) for r in rows] if delete_from_library else [] self.upload_books(gf, names, good, on_card, memory=(_files, remove)) diff --git a/src/calibre/gui2/main_window.py b/src/calibre/gui2/main_window.py index c84ce915fe..f9fbeaac3b 100644 --- a/src/calibre/gui2/main_window.py +++ b/src/calibre/gui2/main_window.py @@ -3,7 +3,7 @@ __copyright__ = '2008, Kovid Goyal ' import StringIO, traceback, sys -from PyQt4.Qt import QMainWindow, QString, Qt, QFont +from PyQt4.Qt import QMainWindow, QString, Qt, QFont, QCoreApplication, SIGNAL from calibre.gui2.dialogs.conversion_error import ConversionErrorDialog from calibre import OptionParser @@ -36,11 +36,17 @@ class MainWindow(QMainWindow): def __init__(self, opts, parent=None): QMainWindow.__init__(self, parent) + app = QCoreApplication.instance() + if app is not None: + self.connect(app, SIGNAL('unixSignal(int)'), self.unix_signal) if getattr(opts, 'redirect', False): self.__console_redirect = DebugWindow(self) sys.stdout = sys.stderr = self.__console_redirect self.__console_redirect.show() + def unix_signal(self, signal): + print 'Received signal:', repr(signal) + def unhandled_exception(self, type, value, tb): try: sio = StringIO.StringIO() diff --git a/src/calibre/utils/filenames.py b/src/calibre/utils/filenames.py new file mode 100644 index 0000000000..cf78d64224 --- /dev/null +++ b/src/calibre/utils/filenames.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +''' +Make strings safe for use as ASCII filenames, while trying to preserve as much +meaning as possible. +''' + +import re, string + + +MAP = { + u"‘" : u"'", + u"’" : u"'", + u"«" : u'"', + u"»" : u'"', + u"…" : u"...", + u"№" : u"#", + u"Щ" : u"Sch", + u"Щ" : u"SCH", + u"Ё" : u"Yo", + u"Ё" : u"YO", + u"Ж" : u"Zh", + u"Ж" : u"ZH", + u"Ц" : u"Ts", + u"Ц" : u"TS", + u"Ч" : u"Ch", + u"Ч" : u"CH", + u"Ш" : u"Sh", + u"Ш" : u"SH", + u"Ы" : u"Yi", + u"Ы" : u"YI", + u"Ю" : u"Yu", + u"Ю" : u"YU", + u"Я" : u"Ya", + u"Я" : u"YA", + u"Б" : u"B", + u"Г" : u"G", + u"Д" : u"D", + u"И" : u"I", + u"Й" : u"J", + u"К" : u"K", + u"Л" : u"L", + u"П" : u"P", + u"Ф" : u"F", + u"Э" : u"E", + u"Ъ" : u"`", + u"Ь" : u"'", + u"щ" : u"sch", + u"ё" : u"yo", + u"ж" : u"zh", + u"ц" : u"ts", + u"ч" : u"ch", + u"ш" : u"sh", + u"ы" : u"yi", + u"ю" : u"yu", + u"я" : u"ya", + u"б" : u"b", + u"в" : u"v", + u"г" : u"g", + u"д" : u"d", + u"з" : u"z", + u"и" : u"i", + u"й" : u"j", + u"к" : u"k", + u"л" : u"l", + u"м" : u"m", + u"н" : u"n", + u"о" : u"o", + u"п" : u"p", + u"т" : u"t", + u"ф" : u"f", + u"э" : u"e", + u"ъ" : u"`", + u"ь" : u"'", + } #: Translation table + +for c in string.whitespace: + MAP[c] = ' ' +PAT = re.compile('['+u''.join(MAP.keys())+']') +print repr('['+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') +