IGN:Fix reading of epub metadata in non GUI threads

This commit is contained in:
Kovid Goyal 2009-04-28 13:24:54 -07:00
parent 939963d366
commit c50e47fdd8
2 changed files with 27 additions and 14 deletions

View File

@ -51,7 +51,7 @@ class OCF(object):
MIMETYPE = 'application/epub+zip' MIMETYPE = 'application/epub+zip'
CONTAINER_PATH = 'META-INF/container.xml' CONTAINER_PATH = 'META-INF/container.xml'
ENCRYPTION_PATH = 'META-INF/encryption.xml' ENCRYPTION_PATH = 'META-INF/encryption.xml'
def __init__(self): def __init__(self):
raise NotImplementedError('Abstract base class') raise NotImplementedError('Abstract base class')
@ -70,13 +70,13 @@ class OCFReader(OCF):
self.container = Container(f) self.container = Container(f)
except KeyError: except KeyError:
raise EPubException("missing OCF container.xml file") raise EPubException("missing OCF container.xml file")
self.opf_path = self.container[OPF.MIMETYPE] self.opf_path = self.container[OPF.MIMETYPE]
try: try:
with closing(self.open(self.opf_path)) as f: with closing(self.open(self.opf_path)) as f:
self.opf = OPF(f, self.root) self.opf = OPF(f, self.root)
except KeyError: except KeyError:
raise EPubException("missing OPF package file") raise EPubException("missing OPF package file")
class OCFZipReader(OCFReader): class OCFZipReader(OCFReader):
def __init__(self, stream, mode='r', root=None): def __init__(self, stream, mode='r', root=None):
@ -93,19 +93,19 @@ class OCFZipReader(OCFReader):
def open(self, name, mode='r'): def open(self, name, mode='r'):
return StringIO(self.archive.read(name)) return StringIO(self.archive.read(name))
class OCFDirReader(OCFReader): class OCFDirReader(OCFReader):
def __init__(self, path): def __init__(self, path):
self.root = path self.root = path
super(OCFDirReader, self).__init__() super(OCFDirReader, self).__init__()
def open(self, path, *args, **kwargs): def open(self, path, *args, **kwargs):
return open(os.path.join(self.root, path), *args, **kwargs) return open(os.path.join(self.root, path), *args, **kwargs)
class CoverRenderer(QObject): class CoverRenderer(QObject):
WIDTH = 600 WIDTH = 600
HEIGHT = 800 HEIGHT = 800
def __init__(self, path): def __init__(self, path):
if QApplication.instance() is None: if QApplication.instance() is None:
QApplication([]) QApplication([])
@ -123,7 +123,7 @@ class CoverRenderer(QObject):
self.rendered = False self.rendered = False
url = QUrl.fromLocalFile(os.path.normpath(path)) url = QUrl.fromLocalFile(os.path.normpath(path))
self.page.mainFrame().load(url) self.page.mainFrame().load(url)
def render_html(self, ok): def render_html(self, ok):
try: try:
if not ok: if not ok:
@ -158,6 +158,8 @@ class CoverRenderer(QObject):
def get_cover(opf, opf_path, stream): def get_cover(opf, opf_path, stream):
from calibre.gui2 import is_ok_to_use_qt
if not is_ok_to_use_qt(): return None
spine = list(opf.spine_items()) spine = list(opf.spine_items())
if not spine: if not spine:
return return
@ -172,7 +174,7 @@ def get_cover(opf, opf_path, stream):
return return
cr = CoverRenderer(cpage) cr = CoverRenderer(cpage)
return cr.image_data return cr.image_data
def get_metadata(stream, extract_cover=True): def get_metadata(stream, extract_cover=True):
""" Return metadata as a :class:`MetaInformation` object """ """ Return metadata as a :class:`MetaInformation` object """
stream.seek(0) stream.seek(0)
@ -194,11 +196,11 @@ def set_metadata(stream, mi):
reader.opf.smart_update(mi) reader.opf.smart_update(mi)
newopf = StringIO(reader.opf.render()) newopf = StringIO(reader.opf.render())
safe_replace(stream, reader.container[OPF.MIMETYPE], newopf) safe_replace(stream, reader.container[OPF.MIMETYPE], newopf)
def option_parser(): def option_parser():
parser = get_parser('epub') parser = get_parser('epub')
parser.remove_option('--category') parser.remove_option('--category')
parser.add_option('--tags', default=None, parser.add_option('--tags', default=None,
help=_('A comma separated list of tags to set')) help=_('A comma separated list of tags to set'))
parser.add_option('--series', default=None, parser.add_option('--series', default=None,
help=_('The series to which this book belongs')) help=_('The series to which this book belongs'))
@ -240,17 +242,17 @@ def main(args=sys.argv):
if opts.language is not None: if opts.language is not None:
mi.language = opts.language mi.language = opts.language
changed = True changed = True
if changed: if changed:
set_metadata(stream, mi) set_metadata(stream, mi)
print unicode(get_metadata(stream, extract_cover=False)).encode('utf-8') print unicode(get_metadata(stream, extract_cover=False)).encode('utf-8')
if mi.cover_data[1] is not None: if mi.cover_data[1] is not None:
cpath = os.path.splitext(os.path.basename(args[1]))[0] + '_cover.jpg' cpath = os.path.splitext(os.path.basename(args[1]))[0] + '_cover.jpg'
with open(cpath, 'wb') as f: with open(cpath, 'wb') as f:
f.write(mi.cover_data[1]) f.write(mi.cover_data[1])
print 'Cover saved to', f.name print 'Cover saved to', f.name
return 0 return 0
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -3,7 +3,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
""" The GUI """ """ The GUI """
import os import os
from PyQt4.QtCore import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, QSize, \ from PyQt4.QtCore import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, QSize, \
QByteArray, QUrl, QTranslator, QCoreApplication QByteArray, QUrl, QTranslator, QCoreApplication, QThread
from PyQt4.QtGui import QFileDialog, QMessageBox, QPixmap, QFileIconProvider, \ from PyQt4.QtGui import QFileDialog, QMessageBox, QPixmap, QFileIconProvider, \
QIcon, QTableView, QApplication, QDialog QIcon, QTableView, QApplication, QDialog
@ -457,11 +457,14 @@ try:
except: except:
SingleApplication = None SingleApplication = None
gui_thread = None
class Application(QApplication): class Application(QApplication):
def __init__(self, args): def __init__(self, args):
qargs = [i.encode('utf-8') if isinstance(i, unicode) else i for i in args] qargs = [i.encode('utf-8') if isinstance(i, unicode) else i for i in args]
QApplication.__init__(self, qargs) QApplication.__init__(self, qargs)
gui_thread = QThread.currentThread()
self.translator = QTranslator(self) self.translator = QTranslator(self)
lang = get_lang() lang = get_lang()
if lang: if lang:
@ -470,3 +473,11 @@ class Application(QApplication):
self.translator.loadFromData(data) self.translator.loadFromData(data)
self.installTranslator(self.translator) self.installTranslator(self.translator)
def is_ok_to_use_qt():
global gui_thread
if QApplication.instance() is None:
QApplication([])
if gui_thread is None:
gui_thread = QThread.currentThread()
return gui_thread is QThread.currentThread()