diff --git a/resources/images/document-encrypt.png b/resources/images/document-encrypt.png new file mode 100644 index 0000000000..0774342024 Binary files /dev/null and b/resources/images/document-encrypt.png differ diff --git a/resources/recipes/globe_and_mail.recipe b/resources/recipes/globe_and_mail.recipe index 4cc76688c1..22cb6fa5bb 100644 --- a/resources/recipes/globe_and_mail.recipe +++ b/resources/recipes/globe_and_mail.recipe @@ -8,12 +8,13 @@ __docformat__ = 'restructuredtext en' globeandmail.com ''' +import re + from calibre.web.feeds.news import BasicNewsRecipe class AdvancedUserRecipe1287083651(BasicNewsRecipe): title = u'Globe & Mail' - __license__ = 'GPL v3' - __author__ = 'Szing' + __author__ = 'Kovid Goyal' oldest_article = 2 no_stylesheets = True max_articles_per_feed = 100 @@ -38,24 +39,19 @@ class AdvancedUserRecipe1287083651(BasicNewsRecipe): (u'Sports', u'http://www.theglobeandmail.com/auto/?service=rss') ] - keep_only_tags = [ - dict(name='h1'), - dict(name='h2', attrs={'id':'articletitle'}), - dict(name='p', attrs={'class':['leadText', 'meta', 'leadImage', 'redtext byline', 'bodyText']}), - dict(name='div', attrs={'class':['news','articlemeta','articlecopy']}), - dict(name='id', attrs={'class':'article'}), - dict(name='table', attrs={'class':'todays-market'}), - dict(name='header', attrs={'id':'leadheader'}) - ] + preprocess_regexps = [ + (re.compile(r'', re.DOTALL), lambda m: ''), + (re.compile(r'', re.DOTALL), lambda m: ''), + ] + remove_tags_before = dict(name='h1') remove_tags = [ - dict(name='div', attrs={'id':['tabInside', 'ShareArticles', 'topStories']}) - ] - - #this has to be here or the text in the article appears twice. - remove_tags_after = [dict(id='article')] + dict(name='div', attrs={'id':['ShareArticles', 'topStories']}), + dict(href=lambda x: x and 'tracking=' in x), + {'class':['articleTools', 'pagination', 'Ads', 'topad', + 'breadcrumbs', 'footerNav', 'footerUtil', 'downloadlinks']}] #Use the mobile version rather than the web version def print_version(self, url): - return url + '&service=mobile' + return url.rpartition('?')[0] + '?service=mobile' diff --git a/src/calibre/ebooks/rtf/input.py b/src/calibre/ebooks/rtf/input.py index ba13668eb7..92ac8a2519 100644 --- a/src/calibre/ebooks/rtf/input.py +++ b/src/calibre/ebooks/rtf/input.py @@ -190,12 +190,11 @@ class RTFInput(InputFormatPlugin): return name def rasterize_wmf(self, name): - raise ValueError('Conversion of WMF images not supported') - from calibre.utils.wmf import extract_raster_image + from calibre.utils.wmf.parse import wmf_unwrap with open(name, 'rb') as f: data = f.read() - data = extract_raster_image(data) - name = name.replace('.wmf', '.jpg') + data = wmf_unwrap(data) + name = name.replace('.wmf', '.png') with open(name, 'wb') as f: f.write(data) return name diff --git a/src/calibre/gui2/dialogs/drm_error.py b/src/calibre/gui2/dialogs/drm_error.py new file mode 100644 index 0000000000..5fbba47165 --- /dev/null +++ b/src/calibre/gui2/dialogs/drm_error.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai + +__license__ = 'GPL v3' +__copyright__ = '2011, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + + +from PyQt4.Qt import QDialog +from calibre.gui2.dialogs.drm_error_ui import Ui_Dialog + +class DRMErrorMessage(QDialog, Ui_Dialog): + + def __init__(self, parent=None, title=None): + QDialog.__init__(self, parent) + self.setupUi(self) + if title is not None: + t = unicode(self.msg.text()) + self.msg.setText('

%s

%s'%(title, t)) + self.resize(self.sizeHint()) + diff --git a/src/calibre/gui2/dialogs/drm_error.ui b/src/calibre/gui2/dialogs/drm_error.ui new file mode 100644 index 0000000000..842807c9bc --- /dev/null +++ b/src/calibre/gui2/dialogs/drm_error.ui @@ -0,0 +1,102 @@ + + + Dialog + + + + 0 + 0 + 417 + 235 + + + + This book is DRMed + + + + + + + 0 + 0 + + + + + 132 + 16777215 + + + + + + + :/images/document-encrypt.png + + + + + + + <p>This book is locked by <b>DRM</b>. To learn more about DRM and why you cannot read or convert this book in calibre, +<a href="http://bugs.calibre-ebook.com/wiki/DRM">click here</a>. + + + true + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index a6eeabd57f..01d3180778 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -468,12 +468,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ try: if 'calibre.ebooks.DRMError' in job.details: if not minz: - d = error_dialog(self, _('Conversion Error'), - _('

Could not convert: %s

It is a ' - 'DRMed book. You must first remove the ' - 'DRM using third party tools.')%\ - (job.description.split(':')[-1], - 'http://bugs.calibre-ebook.com/wiki/DRM')) + from calibre.gui2.dialogs.drm_error import DRMErrorMessage + d = DRMErrorMessage(self, job.description.split(':')[-1]) d.setModal(False) d.show() self._modeless_dialogs.append(d) diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py index 6468cd88c6..c5001659a0 100644 --- a/src/calibre/gui2/viewer/main.py +++ b/src/calibre/gui2/viewer/main.py @@ -627,9 +627,8 @@ class EbookViewer(MainWindow, Ui_EbookViewer): QApplication.processEvents() if worker.exception is not None: if isinstance(worker.exception, DRMError): - error_dialog(self, _('DRM Error'), - _('

This book is protected by DRM') - %'http://wiki.mobileread.com/wiki/DRM').exec_() + from calibre.gui2.dialogs.drm_error import DRMErrorMessage + DRMErrorMessage(self).exec_() else: r = getattr(worker.exception, 'reason', worker.exception) error_dialog(self, _('Could not open ebook'), diff --git a/src/calibre/utils/wmf/parse.py b/src/calibre/utils/wmf/parse.py new file mode 100644 index 0000000000..c618884e33 --- /dev/null +++ b/src/calibre/utils/wmf/parse.py @@ -0,0 +1,269 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai + +__license__ = 'GPL v3' +__copyright__ = '2011, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +import sys, struct + + + +class WMFHeader(object): + + ''' + For header documentation, see + http://www.skynet.ie/~caolan/publink/libwmf/libwmf/doc/ora-wmf.html + ''' + + def __init__(self, data, log, verbose): + self.log, self.verbose = log, verbose + offset = 0 + file_type, header_size, windows_version = struct.unpack_from(' 0: + params = data[offset:offset+delta] + offset += delta + + func = self.function_map.get(func, func) + + if self.verbose > 3: + self.log.debug('WMF Record:', size, func) + self.records.append((func, params)) + + for rec in self.records: + f = getattr(self, rec[0], None) + if callable(f): + f(rec[1]) + elif self.verbose > 2: + self.log.debug('Ignoring record:', rec[0]) + + self.has_raster_image = len(self.bitmaps) > 0 + + + def SetMapMode(self, params): + if len(params) == 2: + self.map_mode = struct.unpack('